public static void main(String[] args) {
Timestamp ts = new Timestamp(116, 02, 12, 20, 45, 0, 0);
Date d = new Date();
d.setTime(ts.getTime());
System.out.println(d);
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
simpleDateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
//System.out.println(ts.getTime());
System.out.println(simpleDateFormat.format(ts));
System.out.println(Timestamp.valueOf(simpleDateFormat.format(ts)));
}
In above code last two lines print different values. Current time zone is CST, I wanted to convert it into UTC. When I convert it Last two lines print different values by one hour i.e., last but one print 13 mar 2:45 am and last print 13 Mar 3:45 am. Why they are different and How can I correct it.
Java 8
Instant inst = LocalDateTime.of(2016, Month.MARCH, 12, 20, 45)
.atZone(ZoneId.of("America/Chicago"))
.toInstant();
System.out.println(inst);
This prints
2016-03-13T02:45:00Z
Today you should not (normally) have a need for a Timestamp object. The java.sql.Timestamp class is long outdated. Once we used it for transferring timestamp values with nanosecond precision to and from SQL databases. Today we use the Instant class for this instead. Instant is one of the classes of java.time, the modern Java date and time API (sometimes we use LocalDateTime from the same API, it depends on your exact requirements and the datatype of your database column).
Neither a Timestamp nor an Instant have a time zone in them. Unlike Timestamp the Instant always prints in UTC (denoted by the Z at the end of the above output). As you can see, the above snippet has correctly converted your time of 20:45 CST to 02:45 the next day UTC.
If you do need a timestamp, typically for a legacy API that you cannot change or don’t want to change just now, conversion is easy:
Timestamp ts = Timestamp.from(inst);
System.out.println(ts);
2016-03-12 20:45:00.0
Timestamp.toString uses the JVM’s time zone setting for generating the string, so you recognize the time we started out from. So the Timestamp contains the correct point in time. There is no need to convert it in any way. If it gets inserted incorrectly into your database, the problem is with your JDBC driver, your database or somewhere else, and you should prefer to correct it there if you can.
Java 6 and 7
Code very similar to the above will work in Java 7 if you add ThreeTen Backport to your project. This is the backport of the java.time classes to Java 6 and 7, and I include a link at the bottom (it’s ThreeTen for JSR-310, where the modern API was first described).
Instant inst = LocalDateTime.of(2016, Month.MARCH, 12, 20, 45)
.atZone(ZoneId.of("America/Chicago"))
.toInstant();
Timestamp ts = DateTimeUtils.toSqlTimestamp(inst);
You notice that the only difference from Java 8 is the way we convert the Instant to a Timestamp. The result is the same, of course.
I you don’t want a dependency on ThreeTen Backport, there are of course still ways to obtain a Timestamp. I wouldn’t use the deprecated constructor, as you do in your code, even though it works as long as no one tampers with your JVM’s time zone setting. If you know you want a Timestamp equal to 02:45 UTC, one option is
Timestamp ts = Timestamp.valueOf("2016-03-12 20:45:00");
It still depends on your JVM’s time zone setting, though.
What went wrong in your code?
As mentioned a Timestamp hasn’t got a time zone in it, so converting a Timestamp to UTC does not make sense.
What happens in your code:
The deprecated Timestamp constructor uses your JVM’s time zone setting (America/Chicago, I presume) for constructing a Timestamp corresponding 12 March 2016 at 8.45 PM in your time zone (the same point in time as 13 March 2:45 AM UTC).
Your SimpleDateFormat correctly formats this into 2016-03-13 02:45:00 (UTC).
Timestamp.valueOf() too uses America/Chicago time zone. However, on the night between 12 and 13 March summer time (daylight saving time) begins in this time zone. At 2 AM the clock is moved forward to 3. So there is no 2:45 this night. Timestamp picks 3:45 instead.
Links
Oracle tutorial: Date Time explaining how to use java.time.
Java Specification Request (JSR) 310, where java.time was first described.
ThreeTen Backport project, the backport of java.timeto Java 6 and 7.
ThreeTenABP, Android edition of ThreeTen Backport
Question: How to use ThreeTenABP in Android Project, with a very thorough explanation.
Related
I am trying to convert time zone, but it's adding one day extra from java function.
"" deActivationDate=2021-06-25T23:59:59.000+0000"";
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
try {
Date date =formatter.parse(deActivationDate);
deActivationDate=formatter.format(date);
LOGGER.info("time format printing 1" +deActivationDate);//2021-06-26T04:29:59.000+0430
deActivationDate = deActivationDate.substring(0, deActivationDate.length()-2)+":30";
LOGGER.info("time format printing 2" +deActivationDate);//2021-06-26T04:29:59.000+04:30""
In above deactivation date is 25 when I am giving input but after formater parase method its converting as 26 why one day os getting add how to avoid it.
java.time through ThreeTen Backport
You should seriously consider using java.time, the modern Java date and time API, for your non-trivial date and time work.
It’s not very clear from your question, but I think that you want to convert the date and time string to the same date and wall-clock time in your own time zone, in this case, Asia/Tehran time zone. So a different point in time: near the end of the day in Iran rather than near the end of the day in UTC. And with a colon in the UTC offset.
I am declaring two formatters, one for parsing without colon and one for formatting back with colon:
private static final DateTimeFormatter PARSER = new DateTimeFormatterBuilder()
.append(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
.appendPattern("xx")
.toFormatter();
private static final DateTimeFormatter PRINTER = new DateTimeFormatterBuilder()
.append(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
.appendPattern("xxx")
.toFormatter();
Now your conversion goes like this:
String deActivationDate = "2021-06-25T23:59:59.000+0000";
OffsetDateTime dateTime = OffsetDateTime.parse(deActivationDate, PARSER);
deActivationDate = dateTime.atZoneSimilarLocal(ZoneId.systemDefault())
.format(PRINTER);
System.out.println("time format printing: " +deActivationDate);
Output is — tested on Java 1.7.0_67 with ThreeTen Backport version 1.3.6:
time format printing: 2021-06-25T23:59:59+04:30
Java knows that Asia/Tehran time zone uses summer time (DST) on June 25, so converts to and prints your desired offset of +04:30. Had the date been in the standard time part of the year, +03:30 would have been printed instead.
The 0 milliseconds are not printed, which for most purposes is an advantage. The format is ISO 8601, and according to the ISO 8601 standard the fraction of second is optional when it is 0. If you require the millis to be there, use this simpler formatter instead:
private static final DateTimeFormatter PRINTER
= DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss.SSSxxx");
time format printing: 2021-06-25T23:59:59.000+04:30
Half-open: You should not represent the end of the day by 1 second before the start of the new day. First, it’s wrong: the day does not end a second before it ends. Second, it may give rise to errors because of times that fall within that last second and therefore in your program will neither belong to one day or the other. Even if this does not happen in practice, you will have programmers wasting their time wondering whether it may happen. Instead represent the end of the day as the first moment of the following day exclusive (typically 00:00). When testing, require a time to be strictly before the end of the day to belong to the day. This approach is standard for all kinds of intervals and certainly for time intervals. They are then known as half-open intervals.
Question: Doesn’t java.time require Java 8?
java.time works nicely on Java 7. It just requires at least Java 6.
In Java 8 and later and on newer Android devices (from API level 26) the modern API comes built-in.
In non-Android Java 6 and 7 get the ThreeTen Backport, the backport of the modern classes (ThreeTen for JSR 310; see the links at the bottom).
On older Android either use desugaring or the Android edition of ThreeTen Backport. It’s called ThreeTenABP. In the latter case make sure you import the date and time classes from org.threeten.bp with subpackages.
Links
Oracle tutorial: Date Time explaining how to use java.time.
Java Specification Request (JSR) 310, where java.time was first described.
ThreeTen Backport project, the backport of java.time to Java 6 and 7 (ThreeTen for JSR-310).
Java 8+ APIs available through desugaring
ThreeTenABP, Android edition of ThreeTen Backport
Question: How to use ThreeTenABP in Android Project, with a very thorough explanation.
Wikipedia article: ISO 8601
Here's the fix for your code. Though we recommend not to do it via substring method.
String deActivationDate="2021-06-25T23:59:59.000+0000";
try {
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
formatter.setTimeZone(TimeZone.getTimeZone("UTC"));
Date date =formatter.parse(deActivationDate);
deActivationDate=formatter.format(date);
System.out.println("time format printing 1: " +deActivationDate);
//2021-06-25T23:59:59.000+0000
deActivationDate = deActivationDate.substring(0,
deActivationDate.length()-4)+"0430";
System.out.println("time format printing 2: " +deActivationDate);
//2021-06-25T23:59:59.000+0430
} catch (Exception e) {
System.err.println(e.getMessage());
}
Thanks to all for your suggestion #beshambher-chaukhwan m i have achieved changes with below code
String deActivationDate="2021-06-25T23:59:59.000+0000";
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
try {
formatter.setTimeZone(TimeZone.getTimeZone("UTC"));
Date date =formatter.parse(deActivationDate);
deActivationDate=formatter.format(date);
if(TimeZone.getDefault().useDaylightTime()) {
deActivationDate = deActivationDate.substring(0, deActivationDate.length()-4)+"04:30";
}else {
deActivationDate = deActivationDate.substring(0, deActivationDate.length()-4)+"03:30";
}
In Android...I am expecting 3:12 pm as time out put of the following code but I get 4:12 pm. Whats the correct way to parse this date time format.
String dt = "2018-09-02T19:12:00-0400";
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
try {
Date date = dateFormat.parse(dt);
System.out.println(date);
} catch (ParseException e) {
e.printStackTrace();
}
Time zone
It’s best to specify explicitly in which time zone you want your output:
DateTimeFormatter inputFormatter
= DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ssXX");
DateTimeFormatter displayFormatter = DateTimeFormatter
.ofLocalizedDateTime(FormatStyle.LONG)
.withLocale(Locale.ENGLISH);
ZoneId displayZone = ZoneId.of("Pacific/Pitcairn");
String dt = "2018-09-02T19:12:00-0400";
OffsetDateTime dateTime = OffsetDateTime.parse(dt, inputFormatter);
String displayDateTime = dateTime.atZoneSameInstant(displayZone)
.format(displayFormatter);
System.out.println(displayDateTime);
This prints:
September 2, 2018 at 3:12:00 PM PST
I have used Pacific/Pitcairn time zone in my code, but you know better which time zone you want.
I am also using java.time, the modern Java date and time API. The date-time classes you are using, SimpleDateFormat and Date, are considered long outdated, and java.time is so much nicer to work with.
What went wrong in your code?
Your way of parsing your date string is correct and produces the correct Date.
When printing the Date, you are implicitly calling toString. The outdated Date class has a peculiar and confusing toString method: it grabs the JVM’s time zone setting and uses it for producing the string. So depending on your default time zone, you can get any hour of day in the output. So it seems your JVM’s time zone setting didn’t correspond to what you had expected.
Since you expected 3:12 PM from your input of 19:12:00-0400, I take it that you want a time zone that is at offset -08:00 from UTC in September. If for example your default time zone was America/Los_Angeles, the standard time of which is at -08:00, you would get Sun Sep 02 16:12:00 PDT 2018 because summer time (daylight saving time) is in effect in California in September, so the offset is -07:00.
Relying on your JVM’s default time zone is always fragile since the setting may be changed at any time by other parts of your program or by other programs running in the same JVM.
Question: Can I use java.time on Android?
Yes, java.time works nicely on older and newer Android devices. It just requires at least Java 6.
In Java 8 and later and on newer Android devices (from API level 26, I’m told) the modern API comes built-in.
In Java 6 and 7 get the ThreeTen Backport, the backport of the new classes (ThreeTen for JSR 310; see the links at the bottom).
On (older) Android use the Android edition of ThreeTen Backport. It’s called ThreeTenABP. And make sure you import the date and time classes from org.threeten.bp with subpackages.
Links
Oracle tutorial: Date Time explaining how to use java.time.
Java Specification Request (JSR) 310, where java.time was first described.
ThreeTen Backport project, the backport of java.time to Java 6 and 7 (ThreeTen for JSR-310).
ThreeTenABP, Android edition of ThreeTen Backport
Question: How to use ThreeTenABP in Android Project, with a very thorough explanation.
This question already has answers here:
How to set time zone of a java.util.Date?
(12 answers)
Closed 5 years ago.
JVM version is 1.7. Timezone is GMT+3, offset 180 minutes. 1500411600000 corresponds to 7/19/2017, 12:00:00 AM (I've verified this online).
I'm executing the following code to adjust time of a Date instance:
final Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
Date date = new Date(1500411600000L);
calendar.setTime(date);
calendar.set(Calendar.HOUR_OF_DAY, 23);
calendar.set(Calendar.MINUTE, 59);
calendar.set(Calendar.SECOND, 59);
calendar.set(Calendar.MILLISECOND, 999);
date = calendar.getTime();
I expect date to become 7/19/2017, 11:59:59 PM but instead of this I get 7/19/2017, 2:59:59 AM. 3 hours difference - exactly as much as my timezone is different from UTC/GMT, so I suppose that some unnoticed conversion happens here.
Can you please help me to find timezone agnostic code for adjusting time in date?
You are correct that at offset UTC+3 your millisecond value, 1500411600000, corresponds to July 19, 2017 at midnight (start of day). At other offsets it corresponds to other times of day either July 18 or 19.
java.time
Assuming that it is no coincidence that you have got midnight in your own time zone, that the value is really supposed to represent a date, not a time, I recommend you use LocalDate from java.time to represent it:
ZoneId yourTimeZone = ZoneId.of("Europe/Riga");
LocalDate date = Instant.ofEpochMilli(1500411600000L)
.atZone(yourTimeZone)
.toLocalDate();
System.out.println(date);
This prints the expected
2017-07-19
Please either substitute your correct time zone in case it doesn’t happen to be Europe/Riga, or use a ZoneOffset instead: .atOffset(ZoneOffset.ofHoursMinutes(3, 0)) (the other lines are the same).
I suspect you don’t really want the end of the day even though in your question you are trying to set it. If this is for determining whether some point in time is before the end of the day, compare it to the start of the following day and require that it is strictly before. This saves you the trouble with the odd-looking minutes, seconds and fractions of second.
ZonedDateTime startOfNextDay = date.plusDays(1).atStartOfDay(yourTimeZone);
java.time came out in 2014 as a replacement for both the poorly designed date and time classes from Java 1.0 and 1.1 and for Joda-Time, from which much inspiration was drawn. I warmly recommend you use it.
What you tried in the question
I believe your code from the question is also clearer when expressed with java.time:
OffsetDateTime endOfDay = Instant.ofEpochMilli(1500411600000L)
.atOffset(ZoneOffset.UTC)
.with(LocalTime.MAX);
System.out.println(endOfDay);
This prints
2017-07-18T23:59:59.999999999Z
(July 18 at the end of day in UTC; Z at the end denotes UTC). Except for the number of decimals, this is also the result you got. You may have been fooled by the fact that your Date instance is printed something like Wed Jul 19 02:59:59 EEST 2017 (the time zone abbreviation depending on your JVM’s time zone setting). Date.toString() grabs your JVM’s time zone setting and converts the date-time to this time zone for the generated string only; the Date instance itself is not modified and only holds a point on the time line, no time zone.
Question: can I use java.time with my Java version?
Yes you can. You just need to use at least Java 6.
In Java 8 and later the new API comes built-in.
In Java 6 and 7 get the ThreeTen Backport, the backport of the new classes (ThreeTen for JSR 310).
On Android, use the Android edition of ThreeTen Backport. It’s called ThreeTenABP, and there’s a thorough explanation in this question: How to use ThreeTenABP in Android Project.
For learning to use java.time, see the Oracle tutorial or find other resoureces on the net.
You're using Calendar.getInstance(TimeZone.getTimeZone("UTC")), but you have to use the timezone you're in. As you stated GMT+3
Please refer to this thread here which explains the issue regarding Date and timezones.
How to set time zone of a java.util.Date?
The Date object will have the correct adjusted time but when it is displayed, the output will use your local timezone. You can forcefully set the timezone of your JVM using the following code but this may have unintended consequences in other parts of your code.
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
In an ideal world you would use the Java 8 date classes or Joda time library classes both of which provide some simple date manipulation methods.
Java 8 date classes
Use clear. It seems a historical "bug" to me, a time zoned Calendar, where setTime does not alter the zone.
final Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
Date date = new Date(1500411600000L);
calendar.clear(); // To reset _all_ fields, incl. the time zone offset ZONE_OFFSET.
calendar.setTime(date);
calendar.set(Calendar.HOUR_OF_DAY, 23);
calendar.set(Calendar.MINUTE, 59);
calendar.set(Calendar.SECOND, 59);
calendar.set(Calendar.MILLISECOND, 999);
date = calendar.getTime();
Of course this might be the right argument to switch to the new java time API.
The problem is bigger than described in my question. It stems from incorrect managing Date/Time for user's timezone. In my application timestamp was sent in user's timezone and then evaluated to date in server's timezone, but timezone difference was not taken into account. I tried to fix this and faced the issue described in the question.
I listened to the #ThomasEdwin's advice to use Joda Time and I'm happy to share this solution:
long userTimezoneOffset = 180; // it's a parameter submitted by client app
Date date = new Date(1500411600000L); // it's another parameter submitted by client app
final DateTimeZone zone = DateTimeZone.forOffsetMillis((int) TimeUnit.MINUTES.toMillis(userTimezoneOffset));
final DateTimeZone serverZone = DateTimeZone.getDefault();
MutableDateTime dateTime = new MutableDateTime(date, zone);
dateTime.setHourOfDay(23);
dateTime.setMinuteOfHour(59);
dateTime.setSecondOfMinute(59);
dateTime.setMillisOfSecond(999);
dateTime.setZoneRetainFields(serverZone);
date = dateTime.toDate();
// now date.toString() returns expected result
Also I found -Duser.timezone JVM parameter to be quite useful when debugging this issue. See here for a list of supported timezone IDs.
I have a String containing a time in the format: 08:00:00
This time is from US Eastern time and I want to convert it to London's timezone and end up with a String of that time.
I have converted the String to time using
Time.valueOf(t);
However after this I cannot get the timezone to change.
you can displace the time using withZoneSameInstant
LocalTime myLocalTime = LocalTime.parse("08:00:00", DateTimeFormatter.ofPattern("HH:mm:ss"));
LocalTime londonTime = LocalDateTime.of(LocalDate.now(), myLocalTime).atZone(ZoneId.of("America/New_York"))
.withZoneSameInstant(ZoneId.of("Europe/London")).toLocalTime();
System.out.println(myLocalTime);
System.out.println(londonTime);
There are lots of details regarding this question.
The Time class sets the date (day, month and year) to January 1st, 1970. But to convert from EST to London local time, you must consider Daylight Saving Time rules.
The difference in hours is not always the same; it can change depending on the date - considering this year (2017): from January 1st to March 11th, the difference will be 5 hours, then from March 12th to March 25th the difference is 4 hours, then it's back to 5 hours, then in October 29th it's 4 hours and in November 5th is 5 hours again, until the end of the year.
That's because of DST starting and ending in both timezones and at different dates. And each year, these dates change as well, so you need to know the date you're working with, to make the correct conversion.
Another thing is that Java 8 new API uses IANA timezones names (always in the format Region/City, like America/Sao_Paulo or Europe/Berlin).
Avoid using the 3-letter abbreviations (like CST or EST) because they are ambiguous and not standard.
If you're using Java <= 7, you can use the ThreeTen Backport, a great backport for Java 8's new date/time classes. And for Android, there's the ThreeTenABP (more on how to use it here).
The code below works for both.
The only difference is the package names (in Java 8 is java.time and in ThreeTen Backport (or Android's ThreeTenABP) is org.threeten.bp), but the classes and methods names are the same.
In the example below I'm using America/New_York - one of the many timezones that uses EST (there are more than 30 timezones that uses or had used it). You can call ZoneId.getAvailableZoneIds() to check all the timezones and choose one that suits best for your case.
The code is very similar to #ΦXocę 웃 Пepeúpa ツ answer, well, because it's straightforward and there's not much to change. I just wanted to add the insights above.
// timezones for US and UK
ZoneId us = ZoneId.of("America/New_York");
ZoneId uk = ZoneId.of("Europe/London");
// parse the time string
LocalTime localTimeUS = LocalTime.parse("08:00:00");
// the reference date (now is the current date)
LocalDate now = LocalDate.now(); // or LocalDate.of(2017, 5, 20) or any date you want
// the date and time in US timezone
ZonedDateTime usDateTime = ZonedDateTime.of(now, localTimeUS, us);
// converting to UK timezone
ZonedDateTime ukDateTime = usDateTime.withZoneSameInstant(uk);
// get UK local time
LocalTime localTimeUK = ukDateTime.toLocalTime();
System.out.println(localTimeUK);
The output will be 13:00 (the result of localTimeUK.toString()) because toString() omits the seconds if the value is zero.
If you want to always output the seconds, you can use a DateTimeFormatter:
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("HH:mm:ss");
String time = fmt.format(localTimeUK);
In this case, the string time will be 13:00:00.
LocalDate.now() returns the current date using your system's default timezone. If you want the current date in a specific zone, you could've called LocalDate.now(us) (or anyzone you want, or even explicit use the default: LocalDate.now(ZoneId.systemDefault()))
Hi I have a table from which I get a date like "2017-03-24 06:01:33" which is in UTC. In my java program I have to receive it as a string. How to convert it to a local date string using client's offset hour and minute?
I would do:
OffsetDateTime odt = LocalDateTime.parse(dateFromDb, DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss"))
.atOffset(ZoneOffset.UTC);
String localDateString = odt.atZoneSameInstant(ZoneOffset.ofHoursMinutes(5, 30))
.toLocalDateTime()
.toString();
I am assuming you have got the client’s time zone as an offset in hours and minutes. Then you can pass those into from ZoneOffset.ofHoursMinutes(). Beware that if the client time zone uses summer time (daylight savings time) some of the year (as is the case in greater parts of the USA), you need to be sure you get the offset for the time of year where the date falls. Other ways of specifying the client time zone would be ZoneId.systemDefault() or ZoneId.of("Asia/Kolkata") — such would know the summer time rules and hence may be safer.
The code prints:
2017-03-24T11:31:33
You notice it’s five and a half hours ahead of the input string as expected.
If you only require the date, not the time, use toLocalDate() instead of toLocalDateTime().
All of the above requires Java 8. Or the backport of the Java 8 date and time classes to Java 6 and 7, see ThreeTen Backport. If you cannot use Java 8 and do not want to depend on the backport, find your inspiration in this question: Not able to parse UTC date time to EST local time.
Use this
simpleDateFormat.setTimeZone("Your-Client's-Timezone");