I have to obtain OffsetDateTime from a string value
"2008-11-15T17:52:58"
I have tried various ways but it gives this error. Please look at the below code snippet and error and provide the comments.
First way to try :
ZonedDateTime.parse("2008-11-15T17:52:58", DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ")).toOffsetDateTime();
Second try :
OffsetDateTime.parse("2014-06-09T17:15:04+02:00", DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ"));
I am getting this error.
Text '2008-11-15T17: 52: 58' could not be parsed at index 19
Your pattern yyyy-MM-dd'T'HH:mm:ss.SSSZ does not include zone offset to parse +02:00. This format looks like RFC-3339 which is already pre-created in DateTimeFormatter.ISO_DATE_TIME
If you need OffsetDateTime while your input has no offset, you should ask yourself what offset to use.
There is parseBest method in DateTimeFormatter that can try multiple temporal queries and gave you back what it found:
Stream.of("2008-11-15T17:52:58", "2014-06-09T17:15:04+02:00").map(s -> {
return DateTimeFormatter.ISO_DATE_TIME.parseBest(s,
OffsetDateTime::from, LocalDateTime::from);
}).forEach(ta -> {
System.out.println("Type : " + ta.getClass());
System.out.println("Value : " + ta.toString());
});
Here is output:
Type : class java.time.LocalDateTime
Value : 2008-11-15T17:52:58
Type : class java.time.OffsetDateTime
Value : 2014-06-09T17:15:04+02:00
As you can see, your first input 2008-11-15T17:52:58 has no offset info so it can't be parsed into OffsetDateTime. You can easily detect that and call .atOffset(...) if you know what offset to use
Here is modified version to detect missing offset and convert LocalDateTime to OffsetDateTime (if you know what offset to use)
Stream.of("2008-11-15T17:52:58", "2014-06-09T17:15:04+02:00").map(s -> {
return DateTimeFormatter.ISO_DATE_TIME.parseBest(s,
OffsetDateTime::from, LocalDateTime::from);
}).forEach(ta -> {
final OffsetDateTime odt;
if (ta instanceof OffsetDateTime) {
odt = (OffsetDateTime) ta;
} else {
//here is 2-hour offset hardcoded. If you need OffsetDateTime
//you should also know offset somehow
odt = ((LocalDateTime) ta).atOffset(ZoneOffset.ofHours(2));
}
System.out.println("Type : " + odt.getClass());
System.out.println("Value : " + odt.toString());
});
Output
Type : class java.time.OffsetDateTime
Value : 2008-11-15T17:52:58+02:00
Type : class java.time.OffsetDateTime
Value : 2014-06-09T17:15:04+02:00
If you can get your string like 2014-06-09T17:15:04+02:00, then it contains a UTC offset, here +02:00, that is 2 hours 0 minutes. In this case you’re set:
OffsetDateTime parsedDateTime = OffsetDateTime.parse("2014-06-09T17:15:04+02:00");
System.out.println(parsedDateTime);
2014-06-09T17:15:04+02:00
We don’t even need to specify a formatter. The string is in ISO 8601 format, and OffsetDateTime and the other classes of java.time parse the most common ISO 8601 variants as their default.
If you get the string like 2008-11-15T17:52:58, the offset is missing, so it cannot be converted directly to an OffsetDateTime since, as the name says, an OffsetDateTime includes an offset. You cannot assign first and last name to a person if you are only told the first name.
If you know that some known time zone was understood and intended, you may convert to anOffsetDateTime, though. If you know the familiy name of a person’s family, maybe you can assume that it is also this person’s last name? It’s probably easier to understand if we make the conversion explicit in the code. We first parse into a LocalDateTime. Local in some of the class names of java.time means “without time zone or offset”, so this is the right class for your string. And the format is still ISO 8601, so we still don’t need the formatter.
OffsetDateTime calculatedDateTime = LocalDateTime.parse("2008-11-15T17:52:58")
.atZone(ZoneId.of("Asia/Karachi"))
.toOffsetDateTime();
System.out.println(calculatedDateTime);
2008-11-15T17:52:58+05:00
The conversion takes any summer time (DST) and other time changes in the specified time zone into account.
What went wrong in your code?
ZonedDateTime.parse("2008-11-15T17:52:58", DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ")).toOffsetDateTime();
Your pattern yyyy-MM-dd'T'HH:mm:ss.SSSZ requires that your string contains three decimals of fraction on the seconds and a UTC offset without colon, for example 2008-11-15T17:52:58.000+0200. One way to see this is to use the formatter for formatting and printng the result:
System.out.println(ZonedDateTime.now(ZoneId.of("Asia/Kolkata"))
.format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ")));
2021-02-13T02:59:04.324+0530
Since the string you tried to parse neither included fraction of second nor offset, parsing failed.
Your second attempt had the same problem. There still was no fraction of second in your string. This time there was an offset, but with colon between hours and minutes, which a single Z does not match. You might have used xxx for such an offset.
Link
Wikipedia article: ISO 8601
I need to get the System DateTime but do not need the [America/New_York] using the below code.
Any suggestions?
String timestampAtGMT = DateTimeFormatter.ISO_DATE_TIME.withZone(ZoneId.systemDefault()).format(Instant.now());
String dateInAmerica = timestampAtGMT.trim();
System.out.println("In 'GMT-04:00' Time Zone:" + dateInAmerica);
Code Output :
In 'GMT-04:00' Time Zone:2020-03-23T21:39:49.419-04:00[America/New_York]
Expected Output : In 'GMT-04:00' Time Zone:2020-03-23T21:39:49.419-04:00
One solution is to remove .withZone(ZoneId.systemDefault()), and then change Instant.now() to OffsetDateTime.now(). With this, your new snippet looks like:
String timestamp = DateTimeFormatter.ISO_DATE_TIME.format(OffsetDateTime.now());
System.out.println("In 'GMT-04:00' Time Zone: " + timestamp);
And the output is:
In 'GMT-04:00' Time Zone: 2020-03-23T21:52:10.794463-04:00
By default, OffsetDateTime#now uses your system clock's default time-zone, so there's no need to specify it.
I think that what you want is an OffsetDateTime and no formatter. Simply:
String dateInAmerica
= OffsetDateTime.now(ZoneId.systemDefault()).toString();
System.out.println("In 'GMT-04:00' Time Zone:" + dateInAmerica);
When I ran this with my JVM’s time zone set to America/New_York just now, the output I got was:
In 'GMT-04:00' Time Zone:2020-03-24T15:53:11.948127-04:00
An OffsetDateTime is a date and time with an offset (for example -04:00), but without a time zone such as America/New_York. So you get the correct offset for your time zone at this time without getting the time zone.
Technically we could leave out ZoneId.systemDefault(), but I prefer to state it there to tell the reader and myself that I have considered which time zone I want and have made a conscious choice to rely on the JVM default.
I got the following date input Sat May 23 18:09:05 EEST 2015 ,
how can i convert it into this format of json
"PublishedTo":"\/Date(1432645752000+0200)\/"
The seems like the date/time wire format used in WCF. From MSDN it states:
DateTime values appear as JSON strings in the form of
"/Date(700000+0500)/", where the first number (700000 in the example
provided) is the number of milliseconds in the GMT time zone, regular
(non-daylight savings) time since midnight, January 1, 1970. The
number may be negative to represent earlier times. The part that
consists of "+0500" in the example is optional and indicates that the
time is of the Local kind - that is, should be converted to the local
time zone on deserialization. If it is absent, the time is
deserialized as Utc. The actual number ("0500" in this example) and
its sign (+ or -) are ignored.
If so, this issue has been discussed several times on SO.
.net JSON Date format
POSTing a DateTime from Android to a WCF RESTful JSON Service
Try this:
String givenDateString = "5/28/2015";
SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy");
try {
Date mDate = sdf.parse(givenDateString);
long timeInMilliseconds = mDate.getTime();
System.out.println("Date in milli :: " + timeInMilliseconds);
} catch (ParseException e) {
e.printStackTrace();
}
I bumped into this issue today. I have set my clock to UTC-6.00 (Central America) time zone. I am converting the Date "06/01/2015::12:00:00 AM" ("MM/dd/yyyy::hh:mm:ss a" format) to a java Date object. And then I am reconverting the date object to String. There is a slight twist in how I am doing this though. I am listing the re conversion steps below -
Calculate UTC offset from current time zone. (-21600000)
Get all available timezone ids for this offset. (All have same offset)
Select the first time zone id. (Will have same offset)
Set this as the timezone.
Convert the date to string format using Java's Simple Date Format.
I see that the time now rendered is "06/01/2015::01:00:00 AM"
My questions :
Since the timezone offset is same during the creation and during conversion I expect the same time to be shown. But what I see is different. Why is it so?
Imagine the re conversion to be happening in the server and the creation to be happening in the client. I need to render back the same date and time to the client. How do I do this?
Please help! Any help is much appreciated.
EDIT : Following is the code. Note that I have set my current timezone to Central America.
public class TimeTest {
public static void main (String args[]) {
SimpleDateFormat formatter = new SimpleDateFormat("dd/MM/yyyy::hh:mm:ss a");
String dateInString = "01/06/2015::12:00:00 AM";
try {
Date date = formatter.parse(dateInString);
System.out.println("Before conversion --> " + formatter.format(date));
System.out.println("After conversion --> " + convertDateValueIntoString(date));
} catch (ParseException e) {
e.printStackTrace();
}
}
private static String convertDateValueIntoString(Date dateValue){
SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy::hh:mm:ss a");
String date;
int offset = TimeZone.getDefault().getRawOffset();
if (offset == 0) {
dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
date = dateFormat.format(dateValue);
} else {
String TZ[] = TimeZone.getAvailableIDs(offset);
String timeZone = TZ[0];
if (timeZone == null) {
date = dateFormat.format(dateValue);
} else {
TimeZone tz = TimeZone.getTimeZone(timeZone);
dateFormat.setTimeZone(tz);
date = dateFormat.format(dateValue);
}
}
return date;
}
}
Why are the times different:
The difference appears to be in the handling of daylight savings time. Playing around with setting my machine to different time zones and printing the TimeZone toString() I ended up with:
Initial: sun.util.calendar.ZoneInfo[id="America/Tegucigalpa",offset=-21600000,dstSavings=0,useDaylight=false,transitions=9,lastRule=null]
Result: sun.util.calendar.ZoneInfo[id="America/Bahia_Banderas",offset=-21600000,dstSavings=3600000,useDaylight=true,...
Note that these two TimeZones have the same offset, but one uses daylight savings time and the other does not. The offset is all your code is looking at to find an appropriate TimeZone but the date formatting also uses the daylight savings offset.
How do I handle this:
The way every project I've been on that used times did it was to have all internal representation of time be in UTC (or a similar concept). I would have your client convert the time to UTC on input (before sending it to the server), have all server storage use UTC, then when times go back to the client have the client format to the default TimeZone only for output to the user.
That way all your internal times are consistent and all your displayed times are localized for the individual instance of the client, so a user in America/Tegucigalpa may get the time as 12:00 but the user in America/Bahia_Banderas would see 1:00. Both are correct for the users those times would be displayed to.
The Answer by 1337joe is correct. I'll add a few thoughts.
This Question has much confusion floating around.
Time Zone = Offset + Rules/Anomalies/Adjustments
First, a time zone is more than an offset from UTC. A time zone is an offset plus a set of past, present, and future rules about Daylight Saving Time and other anomalies & adjustments.
So whenever possible, use a named time zone rather than a mere offset. And certainly do not mix usage of offset-only with usage of time zones and expect sensible results. That seems to be the core problem in this Question.
So, dig deeper to discover the original intent of the programmers who devised your existing stored data. I suspect they did indeed have a particular time zone in mind rather than a mere offset.
Use Proper Time Zone Names
There is no such time zone as "Central America".
As 1337Joe points out, offsets and time zones vary around Central America. For example, America/Managua is six hours behind UTC while America/Panama is five.
By the way, avoid the 3-4 letter codes for time zones such as "EST" as they are neither standardized nor unique. The one exception is UTC of course.
Specify Your Expected/Desired Time Zone
When [a] you know your incoming data represents a particular time zone or offset, albeit implicitly, and [b] you desire a certain time zone to be applied, do not call on the default time zone. That is asking for trouble. The default time zone can vary by host OS setting on machine by machine. And both the host OS settings can be changed at any time by an admin person. Thirdly, the JVM’s current default time zone can be changed at any moment during runtime by a call to TimeZone.setDefault() by any code in any thread in any app in that same JVM.
So, instead of relying on the default time zone, specify the desired time zone.
Use UTC For Logic & Storage
As 1337joe said, your business logic, data storage, data communication, and database should all be in UTC (almost always). Only apply adjustments to local time zones when expected by the user/consumer.
In comments, the author said their project is already saddled with existing stored data implicitly representing a certain time zone or offset.
java.util.Date toString
The toString method on java.util.Date automatically applies the JVM’s current default time zone. This makes working with time zone adjustments tricky. One of many reasons to avoid using the java.util.Date/.Calendar & java.text.SimpleDateFormat classes.
Use Better Date-Time Library
Use either the new java.time package in Java 8 and later (Tutorial), or the Joda-Time library (which inspired java.time).
Joda-Time
Here is some example code in Joda-Time.
According to the author’s comments, the incoming string implicitly represents a date-time value for a certain known time zone. That time zone is not stated, so I'll arbitrarily use Panama time zone. In this first part, we parse a string while specifying the time zone to be used during parsing and assigned to the resulting object.
DateTimeZone zonePanama = DateTimeZone.forID( "America/Panama" );
DateTimeFormatter formatter = DateTimeFormat.forPattern( "dd/MM/yyyy::hh:mm:ss a" );
String input = "06/01/2015::12:00:00 AM";
DateTime dateTimePanama = formatter.withZone( zonePanama ).parseDateTime( input );
System.out.println( "Input as string: " + input + " becomes object: " + dateTimePanama + " with time zone: " + dateTimePanama.getZone() );
Now let's adjust to UTC. Here this is for demonstration. In real code you would generally do any further work using this UTC value.
DateTime dateTimeUtc = dateTimePanama.withZone( DateTimeZone.UTC );
System.out.println( "dateTimeUtc: " + dateTimeUtc );
For output, our user/consumer expects a String representation in the same Panama time zone and in the same format as our input.
String output = formatter.print( dateTimeUtc.withZone( zonePanama ) );
System.out.println( "Output in special format: " + output );
When run.
Input as string: 06/01/2015::12:00:00 AM becomes object: 2015-01-06T00:00:00.000-05:00 with time zone: America/Panama
dateTimeUtc: 2015-01-06T05:00:00.000Z
Output in special format: 06/01/2015::12:00:00 AM
For question #1: The timezone offset may be the same for different timezones, but the DST may be used or not and this results in a difference.
For question #2:
For the future, you can only be safe about the time when you use UTC. (you can work around, if your time data is "recent" - see below)
For the past, you cannot reliably extract the correct time.
General conversion advice:
I worked on a project dealing with timezones and DST in a JDBC driver. There were problems storing time values and reading them back correctly. I worked /real hard/ trying to get a conversion right, so we could spare the larger works of switching to UTC. There is no correct conversion without UTC. ( /real hard/ : Think of Pulp Fiction where Jules says "I'm trying real hard to be the shepherd." :-) )
Question #2 / Future:
If your client cannot send UTC times (maybe because it is a third party system):
When your server receives time data (non UTC) from the client, which you know to be current within a few minutes (maybe somewhat longer), you could try to use your UTC time and match that to the client's time. Imagine your client sends "2015-06-01 15:45" and you know, it is now "2015-06-01 18:51 UTC", then you may interpret the client's time as "2015-06-01 18:45 UTC". If the time data sent by the client may be older than about an hour, this will fail in some cases.
Or in other words: Say your client records temperature values. If the data sent by the client is not older than a few minutes, you can match that to the UTC time. If your client records temperature of one day and sends you that at the end of the day, you cannot correctly match the time.
Why will you not be able to make a fully(!) correct conversion?
Assume the night when DST changes, so that the clock is changed from 03:00 back to 02:00. You have once 02:30 before the switch and another 02:30 after the switch. The first 02:30 has another UTC time than the second 02:30. So with UTC you are fine. But only with the "client local" 02:30, you will never be sure.
Back to the client data age: If your client sends data not older than a few minutes for 02:30 and then later another for the second 02:30, you can distinguish this on the server. If at 04:00 you get two records for 02:30, you cannot restore UTC any more.
Question #2 / Past:
Can you add a flag in the database so that new times which are transferred as UTC are marked "reliable" and the old values are not?
The output and the source:
The output from running the modified source on my system which has a TZ of "Europe/Berlin". Note that this has DST in use, but the first fetched TZ ("Algiers") has DST not in use.
formatter's TZ is sun.util.calendar.ZoneInfo[id="Europe/Berlin",offset=3600000,dstSavings=3600000,useDaylight=true,transitions=143,lastRule=java.util.SimpleTimeZone[id=Europe/Berlin,offset=3600000,dstSavings=3600000,useDaylight=true,startYear=0,startMode=2,startMonth=2,startDay=-1,startDayOfWeek=1,startTime=3600000,startTimeMode=2,endMode=2,endMonth=9,endDay=-1,endDayOfWeek=1,endTime=3600000,endTimeMode=2]]
internal date value = 1433109600000 as UTC = 31/05/2015::10:00:00 PM
Before conversion --> 01/06/2015::12:00:00 AM
Conversion: offset != 0, using TZ sun.util.calendar.ZoneInfo[id="Africa/Algiers",offset=3600000,dstSavings=0,useDaylight=false,transitions=35,lastRule=null]
After conversion --> 31/05/2015::11:00:00 PM
Setting UTC...
formatter's TZ is sun.util.calendar.ZoneInfo[id="UTC",offset=0,dstSavings=0,useDaylight=false,transitions=0,lastRule=null]
internal date value = 1433116800000 as UTC = 01/06/2015::12:00:00 AM
Before conversion --> 01/06/2015::12:00:00 AM
Conversion: offset != 0, using TZ sun.util.calendar.ZoneInfo[id="Africa/Algiers",offset=3600000,dstSavings=0,useDaylight=false,transitions=35,lastRule=null]
After conversion --> 01/06/2015::01:00:00 AM
The source code:
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;
public class TimeTest {
static TimeZone utc = TimeZone.getTimeZone("UTC");
public static void main (String args[]) {
SimpleDateFormat formatter = new SimpleDateFormat("dd/MM/yyyy::hh:mm:ss a");
String dateInString = "01/06/2015::12:00:00 AM";
SimpleDateFormat utcformatter = new SimpleDateFormat("dd/MM/yyyy::hh:mm:ss a");
utcformatter.setTimeZone(utc);
try {
Date date = formatter.parse(dateInString);
System.out.println("formatter's TZ is " + formatter.getTimeZone());
System.out.println("internal date value = " + date.getTime() + " as UTC = " + utcformatter.format(date));
System.out.println("Before conversion --> " + formatter.format(date));
System.out.println("After conversion --> " + convertDateValueIntoString(date));
System.out.println("\nSetting UTC...\n");
formatter.setTimeZone(utc);
date = formatter.parse(dateInString);
System.out.println("formatter's TZ is " + formatter.getTimeZone());
System.out.println("internal date value = " + date.getTime() + " as UTC = " + utcformatter.format(date));
System.out.println("Before conversion --> " + formatter.format(date));
System.out.println("After conversion --> " + convertDateValueIntoString(date));
} catch (ParseException e) {
e.printStackTrace();
}
}
private static String convertDateValueIntoString(Date dateValue){
SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy::hh:mm:ss a");
String date;
int offset = TimeZone.getDefault().getRawOffset();
if (offset == 0) {
System.out.println("Conversion: offset == 0 -- setting UTC");
dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
date = dateFormat.format(dateValue);
} else {
String TZ[] = TimeZone.getAvailableIDs(offset);
String timeZone = TZ[0];
if (timeZone == null) {
System.out.println("Conversion: offset != 0, did not find TZ, tz of dateFormat is " + dateFormat.getTimeZone());
date = dateFormat.format(dateValue);
} else {
TimeZone tz = TimeZone.getTimeZone(timeZone);
System.out.println("Conversion: offset != 0, using TZ " + tz);
dateFormat.setTimeZone(tz);
date = dateFormat.format(dateValue);
}
}
return date;
}
}
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.