I have problems with formatting server time. Server is on central time I guess. I need to format following string 2016-08-22T10:29:22 in default zone (Central European Summer Time = GMT+2). I tried with Joda-Time library, I need to get 12:29:22, but I only managed to get same date with +02:00 the end, with code like this:
DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss");
DateTime dateTime = formatter.withZone(DateTimeZone.getDefault()).parseDateTime(time);
Output of this code is: 2016-08-22T10:29:22.000+02:00, when I try to dateTime.getHourOfDay(); - I getting 10 again.
Where am I going wrong?
2016-08-22T10:29:22 in default zone (Central European Summer Time = GMT+2).
10:29 in GMT+2 is 10:29 in GMT+2 and 8:29 in GMT, and the 2016-08-22T10:29:22 simply lacks information of timezone. So either make server return timezone or manually add it (i.e. append Z) prior converting.
Related
I'm trying to convert a date in RFC 1123 format to number of milliseconds from epoch in Java.
My usecase is that I've uploaded a file to my pCloud storage (directly from my browser) and then from java, request the REST API to retrieve the last modified datetime of this file.
The string I've received is "Fri, 08 Apr 2022 15:57:48 +0000".
But from my computer, the file last modification is at 17:57:48.
But I'm in Europe/Paris, so that I'm at timezone offset +2.
I tried to do:
String modified = "Fri, 08 Apr 2022 15:57:48 +0000";
DateTimeFormatter formatter = DateTimeFormatter.RFC_1123_DATE_TIME;
LocalDateTime localDateTime = LocalDateTime.parse(modified, formatter);
ZonedDateTime zdt = ZonedDateTime.of(localDateTime, ZoneId.systemDefault());
At this point, if I output variables:
System.out.println(localDateTime);
System.out.println(zdt);
It displayed:
2022-04-08T15:57:48
2022-04-08T15:57:48+02:00[Europe/Paris]
Now to convert to milliseconds from epoch time, I've tried:
localDateTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
zdt.toInstant().toEpochMilli();
localDateTime.toInstant(OffsetDateTime.now().getOffset()).toEpochMilli();
And all these give
1649426268000
And if I use the following formatter :
new SimpleDateFormat("YYYY/MM/dd HH:mm:ss").format(long milliseconds).
It display:
2022/04/08 15:57:48
So it missing my timezone offset?! (the "+02:00[Europe/Paris]").
I found this solution:
TimeZone tz = TimeZone.getTimeZone(ZoneId.systemDefault());
long milli = zdt.toInstant().toEpochMilli() + tz.getOffset(new Date().getTime())
And formmating milli as just before with the same SimpleDateFormat, I have:
2022/04/08 17:57:48
which is the correct value.
Is there a cleaner way to have the correct long millisecond to epoch from my string date in RFC 1123 format?
Especially I think in my solution I have to do something like
tz.getOffset(extact date from "modified" string)
because the offset is not the same according to DST (summer or winter), and I hope this use case must be natively managed with all the Class of Java ?
You are using a LocalDateTime, which stores only date and time components. Then you proceed to apply the local time zone. Your local time zone is not relevant to this task, so should not be used.
Instead, since your input contains a date, time, and offset, you should parse to an OffsetDateTime.
String modified = "Fri, 08 Apr 2022 15:57:48 +0000";
DateTimeFormatter formatter = DateTimeFormatter.RFC_1123_DATE_TIME;
OffsetDateTime odt = OffsetDateTime.parse(modified, formatter);
Then you can use either of the following to get milliseconds since the epoch:
odt.toInstant().toEpochMilli()
or
odt.toEpochSecond() * 1000
Either will give you the correct value of 1649433468000. See similar code run live at IdeOne.com.
(Note, there is no toEpochMilli method directly on an OffsetDateTime, so either go through an Instant first, or get seconds and multiply by 1000.)
In Java 8 I need a way to get the local datetime (GMT+1) from a GMT datetime in ISO 8601 format.
A simple example:
Client sends me (Server) this datetime "2020-01-11T23:00:00.000Z"
Client sends me this when the user choose the 12 Jan 2020 from the datepicker. Is the 12 Jan for GMT+1 but the day before for GMT.
For the reason above then I know that for me this datetime is not the 11 Jan 2020 but 12 Jan 2020 in GMT+1.
So I need this value "2020-01-12T00:00:00.000"
To be precise I don't need to print this with simpleDateFormat but just covert "2020-01-11T23:00:00.000Z" to "2020-01-12T00:00:00.000" in a java.util.Date class field
Thanks.
The problem is that the source system took the pure date value, but added time at midnight, then converted that to UTC, but you want the pure date value in a java.util.Date, which by default prints in your local time zone, i.e. the JVM's default time zone.
So, you have to parse the string, revert the value back to the time zone of the source system, the treat that local time as a time in your own JVM's default time zone.
You can do that like this, showing all the intermediate types:
String sourceStr = "2020-01-11T23:00:00.000Z";
ZoneId sourceTimeZone = ZoneOffset.ofHours(1); // Use real zone of source, e.g. ZoneId.of("Europe/Paris");
// Parse Zulu date string as zoned date/time in source time zone
Instant sourceInstant = Instant.parse(sourceStr);
ZonedDateTime sourceZoned = sourceInstant.atZone(sourceTimeZone);
// Convert to util.Date in local time zone
ZonedDateTime localZoned = sourceZoned.withZoneSameLocal(ZoneId.systemDefault());
Instant localInstant = localZoned.toInstant();
Date localDate = Date.from(localInstant); // <== This is your desired result
// Print value in ISO 8601 format
String localStr = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS").format(localDate);
System.out.println(localStr);
Output
2020-01-12T00:00:00.000
The code can of course be merged together:
String input = "2020-01-11T23:00:00.000Z";
Date date = Date.from(Instant.parse(input).atZone(ZoneOffset.ofHours(1))
.withZoneSameLocal(ZoneId.systemDefault()).toInstant());
System.out.println(date);
Output
Sun Jan 12 00:00:00 EST 2020
As you can see, the date value is correct, even though I'm in the US Eastern time zone.
I'm about to deal with time zones in Grails (Java). Here Java 7 is used and Grails 2.3.7.
I have a WebApp where each user is assigned a timeZoneID. If a user enters a date, it only consists of day, month and year. I want to set the time automatically.
The date entered by the user (e.g. 01.10.2018, german format) should be saved in the DB (MySQL) in UTC format.
When the date is displayed to the user, it is formatted according to the user's time zone.
Many timeZoneIDs work fine with my code (Europe/Berlin, Hont_Kong, ....), but America/New_York for example doesn't and I don't understand why.
The code to parse and save a date is as follows:
//endDate is 31.10.2018
def format = messageService.getMessage(code: 'default.date.short.format')
//--> dd.MM.yyyy for DE and MM/dd/yy for EN
println("Use format: " + format)
SimpleDateFormat sdf = new SimpleDateFormat(format);
//set timezone (America/New_York)
sdf.setTimeZone(TimeZone.getTimeZone(user.timeZoneID))
//parse endDate
Date parsedEndDate = sdf.parse(endDate)
//create a calendar instance (e.g. America/New_York)
Calendar calendarEnd = Calendar.getInstance(TimeZone.getTimeZone(user.timeZoneID));
//set time
calendarEnd.setTime(parsedEndDate);
//set hour/minute automatically
calendarEnd.set(Calendar.HOUR_OF_DAY, 23)
calendarEnd.set(Calendar.MINUTE, 59)
//at this point it should be 31.10.2018, 23:59 (german format, timezone America/New_York)
//Convert to UTC before saving date in DB (MySQL)
calendarEnd.setTimeZone(TimeZone.getTimeZone('UTC'))
//save the date
def obj = new Foo(date:calendarEnd).save(flush:true)
The code inside my view (gsp) to display a date is as follows:
<g:formatDate
timeZone="${user.timeZoneID}"
date="${fooInstance?.calendarEnd}"
format="${message(code: 'default.date.format', default: 'MM/dd/yyyy, hh:mm a')}"/>
Inside the DB I get 2018-11-01 00:59:00
Inside my view (GSP) it results in 31.10.2018, 19:59, instead of 31.10.2018, 23:59
Thank you very much for your help.
The problem is in convert step:
//Convert to UTC before saving date in DB (MySQL)
calendarEnd.setTimeZone(TimeZone.getTimeZone('UTC'))
Because you are just changing the time zone so it is using the given time and date as if it is the UTC time zone.
Java 1.7 and before are somewhat unwieldy in regards to the Time API so a lot of people use Joda Time.
Otherwise you can use the advice from this question resulting in something like:
calendarEnd.add(Calendar.MILLISECOND, TimeZone.getTimeZone('UTC').getOffset(parsedEndDate.getTime())
This is not tested and could be wrong as the offset calculation might be diffrent
For getting timezone offset of Singapore, if I try "Singapore" as ID, I will get correct one as like below:
TimeZone timeZone = TimeZone.getTimeZone("Singapore");
int offset = timeZone.getRawOffset();//It prints 28800000 which is correct
But If try SGT in place of Singapore as below, It will return offset of GMT because it does not understand SGT as id:
TimeZone timeZone = TimeZone.getTimeZone("SGT");
int offset = timeZone.getRawOffset();//It prints 0 which is incorrect and should be 28800000
Any way for getting correct offset for Singapore by using "SGT" in place of "Singapore"????
Above issue is not produced for ID "America/Los_Angeles". "PST" and "America/Los_Angeles" returns same offset.
Regards
EDITED--
If I have date like "2015-02-08 11:18 AM SGT" then ?????
Still am I not able to get offset of "Singapore" using above date?
Trying to get how I can make possible.
Not all three-letter IDs seem to be supported, as stated in the docs:
For compatibility with JDK 1.1.x, some other three-letter time zone IDs (such as "PST", "CTT", "AST") are also supported. However, their use is deprecated [...]
As #duckstep says, just a few short names are supported.
So, you must use Asia/Singapore, e.g.:
Code:
TimeZone timeZone = TimeZone.getTimeZone("Asia/Singapore");
System.out.println(timeZone.getID());
System.out.println(timeZone.getRawOffset());
System.out.println(timeZone.getDisplayName(false, TimeZone.LONG));
System.out.println(timeZone.getDisplayName(false, TimeZone.SHORT));
System.out.println(timeZone.getDisplayName(true, TimeZone.LONG));
System.out.println(timeZone.getDisplayName(true, TimeZone.SHORT));
Output:
Asia/Singapore
28800000
Singapore Time
SGT
Singapore Summer Time
SGST
I ran into a strange issue. Here is a snippet of code that describes it:
DateTimeZone dtz = DateTimeZone.forOffsetHours(0);
DateTime dt = new DateTime(dtz);
System.out.println(dt);
System.out.println(dt.toDate());
the output is:
2012-02-29T17:24:39.055Z
Wed Feb 29 19:24:39 EET 2012
I'm located UTC+2, but this action is supposed to create a java.util.Date object which is initialized for UTC time. What am I missing?
Date doesn't know about a time zone at all - it only represents an instant in time (like Joda Time's Instant type). It's just a number of milliseconds since the Unix epoch. When you call Date.toString(), it always uses the system local time zone for converting that into a readable text form.
So there's nothing wrong here - just an expectations failure over either the meaning of java.util.Date or its toString() behaviour, or both.
(As an aside, prefer DateTimeZone.UTC over creating your own.)
To get a JDK Date that matches Joda's DateTimeconvert to LocalDateTimefirst.
As explained in the other answers, the time in milliseconds does not change depending on the timezone:
DateTime local = DateTime.now()
Date localJDK = local.toDate()
assert localJDK.getTime() == local.toInstant().getMillis()
DateTime differentTimeZone = DateTime.now(DateTimeZone.forID('America/Chicago'))
Date localJDK2 = differentTimeZone.toDate()
assert differentTimeZone.toInstant().getMillis() == localJDK2.getTime()
assert localJDK.getTime() == localJDK2.getTime()
Converting a LocalDateTime to Date will change that:
Date differentTimeZoneJDK = differentTimeZone.toLocalDateTime().toDate()
assert localJDK.getTime() != differentTimeZoneJDK.getTime()
The behaviour you want is this:
Date jdkDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(dt.toString("yyyy-MM-dd HH:mm:ss"));
Like Jon noted, JDK date is time zone agnostic. Hope this helps someone.