I have a date as a string 2016-10-07T12:46:23Z and after parsing to Date object using SimpleDateFormat is converted to Fri Oct 07 08:46:22 EDT 2016 which is 1 sec precision off. Debugging that code it came that it was parsed to Fri Oct 07 08:46:22.998 EDT 2016
SimpleDateFormat to parse as looks like
DATE_FORMAT_ISO8601 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'")
DATE_FORMAT_ISO8601.setTimeZone(new SimpleTimeZone(SimpleTimeZone.UTC_TIME, "UTC"));
and the code to parse looks like
String dateStr = valuesArray.getString(0);
values[0] = RESTUtils.DATE_FORMAT_ISO8601.parse(dateStr);
Any tips how to get proper seconds value after parsing?
The expression new SimpleTimeZone(SimpleTimeZone.UTC_TIME, "UTC")) defines an offset not of zero, but 2 milliseconds, see Javadoc, thus explaining the observed result of "Fri Oct 07 08:46:22.998 EDT 2016".
The constant SimpleTimeZone.UTC is not intended to indicate an offset (as mandated as first argument to SimpleTimeZone-constructor). Its numerical value of "2" is rather a mode to denote how to interprete start or end time parameters for other constructors.
Therefore the correct solution to interprete the trailing "Z" in your input (ISO-8601-notation for zero offset) is:
DATE_FORMAT_ISO8601.setTimeZone(TimeZone.getTimeZone("GMT"));
Alternatively, if you really want to use the class SimpleTimeZone:
DATE_FORMAT_ISO8601.setTimeZone(new SimpleTimeZone(0, "UTC"));
And if you are on Java-8, you could also do this:
Instant instant = Instant.parse("2016-10-07T12:46:23Z");
System.out.println(instant); // 2016-10-07T12:46:23Z
System.out.println(Date.from(instant)); // Fri Oct 07 14:46:23 CEST 2016
You are seeing the second difference when you add the time zone as UTC using SimpleTimeZone, if you comment that part out you will get the exact seconds.
String str = "2016-10-07T12:46:24Z";
SimpleDateFormat DATE_FORMAT_ISO8601 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
// DATE_FORMAT_ISO8601.setTimeZone(new SimpleTimeZone(SimpleTimeZone.UTC_TIME, "UTC"));
System.out.println(DATE_FORMAT_ISO8601.parse(str));
SimpleTimeZone is not meant to be used to define the time zone. Per the documentation
SimpleTimeZone is a concrete subclass of TimeZone that represents a
time zone for use with a Gregorian calendar. The class holds an offset
from GMT, called raw offset, and start and end rules for a daylight
saving time schedule. Since it only holds single values for each, it
cannot handle historical changes in the offset from GMT and the
daylight saving schedule, except that the setStartYear method can
specify the year when the daylight saving time schedule starts in
effect.
The correct way to set the timezone is by doing the following
DATE_FORMAT_ISO8601.setTimeZone(TimeZone.getTimeZone("UTC"));
Related
I'm trying to parse the following date ut get a runtime error saying:
java.time.format.DateTimeParseException: Text '2019-11-21-05:00' could not be parsed, unparsed text found at index 10
My input:
String inpDate = "2019-11-20-05:00"
I also tried the following date formats but no luck.
yyyy-MM-ddZ
yyyy-MM-dd Z
Code:
public static final String DATE_FORMAT = "yyyy-MM-dd";
public static final DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern(DATE_FORMAT);
LocalDate localDate = LocalDate.parse(inpDate, dateFormatter);
return Date.from(localDate.atStartOfDay(ZoneId.systemDefault()).toInstant());
How can I get my input to parse correctly?
Use the following format:
public static final String DATE_FORMAT = "yyyy-MM-ddZZZZZ";
It has 5 times the letter "Z". To parse a timezone offset with a colon, you need to provide the letter "Z" 5 times. This may be somewhat hidden away in the Javadoc.
From the Javadoc:
Offset Z: This formats the offset based on the number of pattern letters.
One, two or three letters outputs the hour and minute, without a colon, such as '+0130'. The output will be '+0000' when the offset is zero.
Four letters outputs the full form of localized offset, equivalent to four letters of Offset-O. The output will be the corresponding localized offset text if the offset is zero.
Five letters outputs the hour, minute, with optional second if non-zero, with colon.
It outputs 'Z' if the offset is zero. Six or more letters throws IllegalArgumentException.
It’s easier than you think. The formatter you need is built in. So don’t struggle with writing your own format pattern string.
String inpDate = "2019-11-20-05:00";
LocalDate localDate = LocalDate.parse(inpDate, DateTimeFormatter.ISO_OFFSET_DATE);
System.out.println(Date.from(localDate.atStartOfDay(ZoneId.systemDefault()).toInstant()));
Output in my time zone:
Wed Nov 20 00:00:00 EST 2019
I am assuming that you are only converting to a Date because you need one for a legacy API that you cannot afford to upgrade to java.time just now. Otherwise you should not use Date but stick to the modern API.
Start of day in your time zone or at the offset given in the string?
Edit: Basil Bourque in a comment asked this very knowledgeable question:
Perhaps it would be more true to the intent of the publisher of this
input string to get the first moment of the day as seen in that offset
of 5 hours behind UTC. Is it possible to parse as an OffsetDateTime
with the time-of-day defaulting to first moment of the day (00:00:00)?
(And then convert to java.util.Date if required.)
It’s definitely true. I have chosen to give code that gives the result that I think the code in the question was trying to obtain. If we understand 2019-11-20-05:00 as some unspecified time in the half-open interval from 2019-11-20T00:00-05:00 to 2019-11-21T00:00-05:00, then for some offsets and some default time zones the result from the above code snippet will actually lie outside that interval (typically before it, may also in corner cases fall after it). So this is true to the question (if I understood it correctly) and untrue to the publisher of the original string. If instead we want the start of day at the UTC offset given in the string I would go like this:
TemporalAccessor parsed = DateTimeFormatter.ISO_OFFSET_DATE.parse(inpDate);
Instant startOfDayAtSpecifiedOffset = LocalDate.from(parsed)
.atStartOfDay(ZoneOffset.from(parsed))
.toInstant();
System.out.println(Date.from(startOfDayAtSpecifiedOffset));
Output in my time zone:
Wed Nov 20 06:00:00 CET 2019
I am at offset +01:00 in November, which is why the time here is 06:00 when the day begins at offset -05:00. To illustrate that the choice of time zone or offset may make a great difference, here’s the output from running the latter snippet with Pacific/Kiritimati as default time zone:
Wed Nov 20 19:00:00 LINT 2019
Or in Pacific/Pago_Pago time zone:
Tue Nov 19 18:00:00 SST 2019
So pick carefully what you really want.
What went wrong in your code?
First, LocalDate.parse() and similar parsing methods insist on parsing the entire string or they will throw the exception you saw mentioning unparsed text found at index (some index) (you may use the overloaded DateTimeFormatter.parse(CharSequence, ParsePosition) method for parsing only as much as possible of the string without that exception).
Second, one Z in the format pattern string matches offset without colon, so -0500, not -05:00.
Link: Documentation of DateTimeFormatter.parse(CharSequence, ParsePosition)
String inpDate = "2019-11-20-05:00";
System.out.println(LocalDate.parse(inpDate, DateTimeFormatter.ofPattern("yyyy-MM-dd-hh:mm")));
Will print 2019-11-20.
I am trying to produce a Date object (java.util.Date) from a LocalDate object (java.time.LocalDate) in which I have the following criteria:
Allow a parameter that can subtract a certain number of days from the Date object
Have the Date & Time be the date and time currently in UTC
Have the time at the beginning of the day i.e. 00:00:00
The Timezone stamp (i.e. CDT or UTC) is irrelevant as I remove that from the String
To meet this criteria, I have created a test program, however I am getting interesting results when I modify a certain property of the LocalDate. See code below:
public static void main (String args[]) {
Long processingDaysInPast = 0L;
LocalDate createdDate1 = LocalDate.now(Clock.systemUTC()).minusDays(processingDaysInPast);
LocalDate createdDate2 = LocalDate.now(Clock.systemUTC()).minusDays(processingDaysInPast);
System.out.println(createdDate1);
System.out.println(createdDate1.atStartOfDay().toInstant(ZoneOffset.UTC));
System.out.println(Date.from(createdDate1.atStartOfDay().toInstant(ZoneOffset.UTC)));
System.out.println((createdDate2.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant()));
System.out.println(Date.from(createdDate2.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant()));
}
Output:
2017-08-14
2017-08-14T00:00:00Z
Sun Aug 13 19:00:00 CDT 2017
2017-08-14
2017-08-14T05:00:00Z
Mon Aug 14 00:00:00 CDT 2017
When I add the value Date.from(createdDate1.atStartOfDay().toInstant(ZoneOffset.UTC)) I get the expected output of the date, with a 00:00:00 time field. However, if I do not add this parameter, such as: Date.from(createdDate2.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant()) I get the resulting day before , at 19:00:00 why is this?
My main goal from this is to be able to capture a Date object, with the current UTC Date, and the Time zeroed out (StartOfDay).
When you do:
createdDate2.atStartOfDay().atZone(ZoneId.systemDefault())
First, createdDate2.atStartOfDay() returns a LocalDateTime, which will be equivalent to 2017-08-14 at midnight. A LocalDateTime is not timezone-aware.
When you call atZone(ZoneId.systemDefault()), it creates a ZonedDateTime with the respective date (2017-08-14) and time (midnight) in the system's default timezone (ZoneId.systemDefault()). And in your case, the default timezone is not UTC (it's "CDT", so it's getting midnight at CDT - just do System.out.println(ZoneId.systemDefault()) to check what your default timezone is).
To get the date at midnight in UTC, you can replace the default zone (ZoneId.systemDefault()) with UTC (ZoneOffset.UTC):
Date.from(createdDate2.atStartOfDay().atZone(ZoneOffset.UTC).toInstant())
Or (a shorter version):
Date.from(createdDate2.atStartOfDay(ZoneOffset.UTC).toInstant())
Of course you can also do the same way you did with createdDate1:
Date.from(createdDate2.atStartOfDay().toInstant(ZoneOffset.UTC))
They're all equivalent and will result in midnight at UTC.
Just a quick note: short timezone names like CDT or PST are not real timezones.
The API uses IANA timezones names (always in the format Region/City, like America/Chicago or Europe/Berlin).
Avoid using the 3-letter abbreviations (like CDT or PST) because they are ambiguous and not standard.
There are lots of different timezones that can use CDT as abbreviation. This happens because a timezone is the set of all different offsets that a region had, has and will have during history. Just because many places uses CDT today, it doesn't mean they all used in the past at the same periods, nor that it'll be used by all in the future. As the history differs, a timezone is created for each region.
I have a load of dates that I'd like to store in a database running on a server using BST:
2015-09-23
2024-05-07
2024-03-13
However they are stored in the DB as:
2015-09-23 01:00:00
2024-05-07 01:00:00
2024-03-13 00:00:00 <-- I need this to be 01:00:00
The values are converted to Date prior to being stored in the DB. I noticed the following when debugging:
TimeZone timeZone = Calendar.getInstance().getTimeZone();
System.out.println(timeZone.getDisplayName(false, TimeZone.SHORT));
System.out.println(new SimpleDateFormat("zzz").format(new Date()));
DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd").withZone(DateTimeZone.UTC);
System.out.println(formatter.parseDateTime("2015-09-23").toDate());
System.out.println(formatter.parseDateTime("2024-05-07").toDate());
System.out.println(formatter.parseDateTime("2024-03-13").toDate());
The first two dates are using BST and the last one is GMT. Is is possible to make them all use the same time zone?
GMT
BST
Wed Sep 23 01:00:00 BST 2015
Tue May 07 01:00:00 BST 2024
Wed Mar 13 00:00:00 GMT 2024
First of all, keep in mind that java.util.Date doesn't have a timezone (more details about it can be read here).
What happens is that Date.toString() method uses the system's default timezone to print its value (check the value of TimeZone.getDefault() in your JVM, it'll probably be Europe/London).
And in Europe/London timezone, the offset is equals to UTC in the winter (which is printed as GMT) and is +01:00 in the summer (which is printed as BST, aka British Summer Time). These different 3-letter names denotes the offset change, but it doesn't mean the dates "changed" their timezone.
Also consider that timezone is not only the offset or the name, but the set of all offset changes that occur in a region during history (when the changes occur, and the offsets before and after each change).
So, the dates doesn't have different timezones, because:
In the same timezone there can be more than 1 offset. And some changes in the offset cause the change in the 3-letter name - although the use of these 3-letter names is widely used, they're ambiguous and not standard.
java.util.Date doesn't have a timezone, so it can't change it.
If you want to save these objects in a DB, what you should care about is the timestamp (the number of milliseconds from 1970-01-01T00:00:00Z), which is preserved when converting to Date.
If you check the timestamp millis in the objects created, you'll see that it wasn't changed:
DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd").withZone(DateTimeZone.UTC);
DateTime d1 = formatter.parseDateTime("2015-09-23");
DateTime d2 = formatter.parseDateTime("2024-05-07");
DateTime d3 = formatter.parseDateTime("2024-03-13");
// comparing timestamp millis between DateTime and java.util.Date
System.out.println(d1.getMillis() == d1.toDate().getTime());
System.out.println(d2.getMillis() == d2.toDate().getTime());
System.out.println(d3.getMillis() == d3.toDate().getTime());
All 3 cases above prints true, meaning that they represent the same instant in time (so the dates hasn't changed).
Actually, you can see that all DateTime objects were in UTC:
System.out.println(d1);
System.out.println(d2);
System.out.println(d3);
This prints:
2015-09-23T00:00:00.000Z
2024-05-07T00:00:00.000Z
2024-03-13T00:00:00.000Z
Conclusion:
you can save the Date objects without any problem, as their values are correct
if you want to display the dates to the user, you can use the DateTime objects (and use a DateTimeFormatter if you want a different format), because they don't use the default TimeZone in the toString() method.
Try this:
SimpleTimeZone UTCTimeZone = new SimpleTimeZone(0, "UTC");
TimeZone.setDefault(UTCTimeZone);
All the date object will use UTC as default timezone for you backend code
I try to convert a string into a datetime:
String dateString = "2015-01-14T00:00:00-04:00";
DateTimeFormatter df = DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ssZ");
DateTime dt = df.parseDateTime(dateString);
If I display dt.toDate()
I get: Tue Jan 13 23:00:00 EST 2015
So there is a time problem.
Without the DateTimeFormatter, I get the same issue.
It's getting the correct value - basically 4am UTC, which is midnight in a UTC offset of -04:00 (as per the original text), or 11pm on the previous day for EST (as per the displayed result).
The problem is that you're using java.util.Date.toString(), which always returns the date in the system time zone. Note that a java.util.Date only represents an instant in time - it has no notion of a time zone itself, so its toString() method just uses the system default.
If you want to retain the time zone information (or in this case, the offset from UTC information - you don't have a full time zone) then stick to DateTime instead of converting to Date. Ideally, avoid java.util.Date/java.util.Calendar entirely. Stick to Joda Time and/or java.time.*.
I have a Date Object in following:
Date date=new Date("Mon, 05 May 2014 12:31:12 +0000")
I want to get Timestamp of date Object then :
date.getTime()
1399293072000
but this value not correct , correct value in following :
1399276872000
//*** for get timestamp use of http://www.epochconverter.com ***\\
why ?
First things first, from the JavaDoc for Date
Date(String s)
Deprecated.
As of JDK version 1.1, replaced by DateFormat.parse(String s).
So the constructor you are using has been deprecated since 1997!
Next, onto the JavaDoc for Date.parse which the construtor uses:
It accepts many syntaxes; in particular, it recognizes the IETF
standard date syntax: "Sat, 12 Aug 1995 13:30:00 GMT". It also
understands the continental U.S. time-zone abbreviations, but for
general use, a time-zone offset should be used: "Sat, 12 Aug 1995
13:30:00 GMT+0430" (4 hours, 30 minutes west of the Greenwich
meridian). If no time zone is specified, the local time zone is
assumed. GMT and UTC are considered equivalent.
Empathsis mine.
So, what timezone are you in? Presumably not UTC.
You should specify local time zone while constructing Date object
Example:
Date date=new Date("Mon, 05 May 2014 12:31:12 GMT+0530");
Using Mon, 05 May 2014 12:31:12 +0000 at http://www.epochconverter.com I get 1399285872000 which is different from your timestamp.
Or you're passing different values, or there's a bug somewhere or
The Unix epoch (or Unix time or POSIX time or Unix timestamp) is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT), not counting leap seconds (in ISO 8601: 1970-01-01T00:00:00Z).
where the javadoc for java.util.Date.getTime() doesn't mention leap seconds.