Conversion of a date to epoch Java [duplicate] - java

This question already has answers here:
SimpleDateFormat producing wrong date time when parsing "YYYY-MM-dd HH:mm"
(5 answers)
Closed 4 years ago.
I want to convert 2018-02-21 15:47:35 UTC to epoch UTC form. How do we do it? I am currently in PST.
SimpleDateFormat df = new SimpleDateFormat("YYYY-MM-DD HH:MM:SS");
df.setTimeZone(TimeZone.getTimeZone("UTC"));
date = df.parse(dateString).getTime();
The code above should return the number of milliseconds since January 1, 1970, 00:00:00 GMT, but I'm getting an incorrect value.

The only problem with your code is DateFormat
please check.
https://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html
String dateString = "2018-02-21 15:47:35";
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
df.setTimeZone(TimeZone.getTimeZone("UTC"));
Date date = df.parse(dateString);
long time = date.getTime();
System.out.println(time);
System.out.println(new Date(time));
System.out.println(date);
I'm in PKT so output would differ...
1519228055000
Wed Feb 21 20:47:35 PKT 2018
Wed Feb 21 20:47:35 PKT 2018

Expected: 2018-02-21 15:47:35 UTC is equivalent to 1 519 228 055 000 milliseconds since the epoch of January 1, 1970 at 0:00 UTC.
Observed: Your code in the question gives 1 514 818 800 035. So it’s 4 409 254 965 milliseconds off, a little over 51 days.
The solution:
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss");
date = LocalDateTime.parse("2018-02-21 15:47:35", dtf)
.atOffset(ZoneOffset.UTC)
.toInstant()
.toEpochMilli();
This gives the correct 1 519 228 055 000.
What went wrong?
One of the many troublesome traits of SimpleDateFormat is that with its default settings, if you specify an incorrect format pattern string, it will very often give you an incorrect result and pretend all is well. The modern Java date and time API that I am using in my snippet, is trying somewhat harder to figure out when the pattern doesn’t make sense and tell you it’s wrong somehow. As an example, let’s try your format pattern with the modern DateTimeFormatter:
final DateTimeFormatter dtf = DateTimeFormatter.ofPattern("YYYY-MM-DD HH:MM:SS");
LocalDateTime.parse(dateString, dtf);
This will throw a java.time.format.DateTimeParseException: Text '2018-02-21 15:47:35' could not be parsed at index 14. Index 14 is where 47 is in the string, it was supposed to be the minutes. Apparently 47 doesn’t match MM in the format. If you haven’t figured out yet, check the documentation. It says that uppercase M is for “month-of-year”. So what the formatter is trying to tell you is there are not 47 months in a year. In the documentation you will also find lowercase m for “minute-of-hour”. As you correct the case of the letters in the format pattern string, you will receive other exceptions until you end up with either yyyy-MM-dd HH:mm:ss or uuuu-MM-dd HH:mm:ss (lowercase yyyy is year or era while uuuu is a signed year, both work for years after year 0).
Links
Oracle tutorial: Date Time explaining how to use java.time.
DateTimeFormatter documentation spelling out the uppercase and lowercase letters of format pattern strings.

Also can be done via java8 time library:
String dateString = "2018-02-21 15:47:35";
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss", Locale.ENGLISH);
dateTimeFormatter.withZone(ZoneId.of("UTC"));
LocalDateTime parsedDateTime = LocalDateTime.from(dateTimeFormatter.parse(dateString));
ZonedDateTime timeAtYourZone = parsedDateTime.atZone(ZoneId.systemDefault());
System.out.println(timeAtYourZone.toInstant().toEpochMilli());
System.out.println(timeAtYourZone);

Your pattern must be yyyy-MM-dd HH:mm:ss, as the other answers told you:
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
I just want to add some more details.
First of all, take a look at the patterns description in the javadoc: https://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html
Note that a lowercase y is not the same as the uppercase Y (lowercase is the year, while uppercase is the week year - 2 different fields with completely different definitions)
Also note that uppercase D is the day of the year, while the day of the month (which is what you want) is the lowercase d. And uppercase M is the month, while lowercase m is the minute of hour.
And uppercase S is the milliseconds field, while the seconds are represented by lowercase s.
And SimpleDateFormat's design doesn't help: the class simply tries to parse the string, even if the month field (MM) appears twice in your pattern, while the minutes field doesn't appear (and it's set to a default value of zero - all behind the scenes, without any warning, no indication of error at all).
Conclusion: always read the docs :-)
For Java 8 or higher, consider using the new date API, which is much better because it doesn't have all these behind-the-scenes stuff:
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
.withZone(ZoneOffset.UTC);
long epochMilli = Instant.from(fmt.parse("2018-02-21 15:47:35")).toEpochMilli();
This API will also throw an exception if you use a pattern like YYYY-MM-DD HH:MM:SS, because it will try to parse the minutes value 47 as a month (because uppercase MM will be in the respective position), and 47 is not a valid month.

Related

Java - parse date with AM/PM next to seconds (no space)

I am trying to parse the following kind of date: Dec 12 2001 11:59:59PM.
If the AM/PM wasn't next to the seconds, I would use the following pattern: MMM dd yyyy HH:mm:ss a.
However the AM/PM is ignored with the pattern MMM dd yyyy HH:mm:ssa (and is therefore always interpreted as AM).
I am trying to use a SimpleDateFormat. I tried to specify a locale to no avail.
Is this possible using a SimpleDateFormat or do I need to use an alternative method/external processing? The SimpleDateFormat particularly interests me due to its use in the pattern attribute of the #JsonFormat annotation.
Thanks.
I would like to use java.time API from Java8+ instead of the old Date :
String date = LocalDateTime.now().format(
DateTimeFormatter.ofPattern("MMM dd yyyy hh:mm:ssa", Locale.ENGLISH)
);
or :
DateTimeFormatter format = DateTimeFormatter.ofPattern(
"MMM dd yyyy hh:mm:ssa", Locale.ENGLISH
);
String date = LocalDateTime.of(2001, Month.DECEMBER, 12, 11, 59, 59).format(format);
Outputs
Jun 14 2018 03:01:02PM
Dec 12 2001 11:59:59AM
with AM/PM you want 12 hours hh instead of 24 hours HH.
hh:mm:ss''a
As k/K/h/H influence a too, now everything might work with ssa.
If ssa is still problematic (seemingly a bug), try separating the letters by an empty literal string (single quotes).
The following works:
hh:mm:ssa
It may very well be possible with SimpleDateFormat, but you will probably prefer to use java.time, the modern Java date and time API:
DateTimeFormatter formatter
= DateTimeFormatter.ofPattern("MMM dd uuuu hh:mm:ssa", Locale.ENGLISH);
String dateTimeString = "Dec 12 2001 11:59:59PM";
LocalDateTime dateTime = LocalDateTime.parse(dateTimeString, formatter);
System.out.println(dateTime);
Output:
2001-12-12T23:59:59
As others have said, your problem was not with the lack of a space between seconds and AM/PM marker, but with using uppercase HH for the hours. Uppercase HH is for hour of day from 00 through 23, where what you wanted was lowercase hh for hour within AM or PM from 01 through 12.
And as yet others have said, there are issues with using SimpleDateFormat and its friend Date:
Those classes are long outdated.
Those classes are poorly designed, and SimpleDateFormat in particular is renowned for being troublesome. Your experience is typical and certainly not unusual.
Getting a correct result from SimpleDateFormat requires that either the JVM time zone setting agrees with the time zone understood in the string, or you set the time zone of the SimpleDateFormat to the relevant time zone. The former is hard to guarantee since the time zone setting can be changed any time from another part of your program or from other programs running in the same JVM.
This also means that if you do require an instance of the outdated Date class (for example for a legacy API that you don’t want to change just now), you will need to decide on a time zone for the conversion. Then convert for example like this:
Instant inst = dateTime.atZone(ZoneId.of("America/Metlakatla")).toInstant();
Date oldfashionedDate = Date.from(inst);
System.out.println(oldfashionedDate);
I hesitate to show you the output because Date shows a quite surprising behaviour here.
Thu Dec 13 08:59:59 CET 2001
08:59? On December 13? The conversion has given you the correct point in time. When I print the Date, its toString method is invoked. This in turn uses my JVM’s time zone setting for producing the string, so the output is in a completely different time zone from the one where the conversion happened. So apparently when it’s 23:59 in Metlakatla, it’s already 08:59 the next day in Copenhagen (my time zone; CET in the output is for Central European Time). Had my JVM’s time zone setting been America/Metlakatla too, the output would have agreed more with the expected:
Wed Dec 12 23:59:59 AKST 2001
java.time is more helpful
What you asked SimpleDateFormat to do was to parse a time that had hour of day 11 and PM. This is really self contradictory since PM only begins at hour of day 12. So it would be reasonable to expect an exception from the request. A SimpleDateFormat with standard settings doesn’t give you that. It’s very typical for SimpleDateFOrmat to give you a wrong result and pretend all is well. However let’s for a moment try my modern code with your format pattern string of MMM dd yyyy HH:mm:ssa. Then we get:
Exception in thread "main" java.time.format.DateTimeParseException:
Text 'Dec 12 2001 11:59:59PM' could not be parsed: Conflict found:
Field AmPmOfDay 0 differs from AmPmOfDay 1 derived from 11:59:59
I don’t claim I understand exactly why it is worded like this, but it is mentioning a conflict in the AM/PM, which is exactly what we have.
PS
I hadn’t thought at first that I’d contribute an answer, but in the end I was provoked by on one hand bohemian’s comment that only Joop Eggen’s answer was correct and on the other hand a couple of comments by Basil Bourque claiming that you could not use the SimpleDateFormat that Joop Eggen was using. So I wanted to set things straight.
Link
Oracle tutorial: Date Time explaining how to use java.time.
Java internally uses the builder pattern. This is slightly modified from the source code of DateTimeFormatter.RFC_1123_DATE_TIME:
I don't recommend using this over the alternative, DateTimeFormatter.ofPattern(), but it can prove more powerful in certain scenarios where you hit the limitations of ofPattern.
Map<Long, String> moy = new HashMap<>();
moy.put(1L, "Jan"); moy.put(2L, "Feb"); moy.put(3L, "Mar");
moy.put(4L, "Apr"); moy.put(5L, "May"); moy.put(6L, "Jun");
moy.put(7L, "Jul"); moy.put(8L, "Aug"); moy.put(9L, "Sep");
moy.put(10L, "Oct"); moy.put(11L, "Nov"); moy.put(12L, "Dec");
DateTimeFormatter format = new DateTimeFormatterBuilder()
.appendText(MONTH_OF_YEAR, moy)
.appendLiteral(' ')
.appendValue(DAY_OF_MONTH, 2)
.appendLiteral(' ')
.appendValue(YEAR, 4, 4, EXCEEDS_PAD)
.appendLiteral(' ')
.appendValue(HOUR_OF_AMPM, 1, 2, NOT_NEGATIVE)
.appendLiteral(':')
.appendValue(MINUTE_OF_HOUR, 1, 2, NOT_NEGATIVE)
.optionalStart()
.appendLiteral(':')
.appendValue(SECOND_OF_MINUTE, 1, 2, NOT_NEGATIVE)
.optionalEnd()
.appendText(AMPM_OF_DAY)
.toFormatter();
System.out.println(format.parse("Jun 14 2018 2:51:22AM")); // {},ISO resolved to 2018-06-14T02:51:22
System.out.println(format.parse("Jun 14 2018 2:51:22PM")); // {},ISO resolved to 2018-06-14T14:51:22
Note
Unfortunately, the below code is inaccurate. AM/PM marker is never read. Depending on the local time, either AM or PM is assumed.
Original answer
Use the following format string "MMM dd yyyy HH:mm:ssaaa".
String str = "Jun 14 2018 13:53:19PM";
DateFormat df = new SimpleDateFormat("MMM dd yyyy HH:mm:ssaaa");
try {
Date date = df.parse(str);
System.out.print(df.format(date));
} catch (ParseException e) {
e.printStackTrace();
}

Not able to understand "YYYY-MM-DDTHH:MM:SS" date format

I am trying to parse following date time string
2018-01-30T23:59:59.000
I am not able to understand which standard format it is like UTC or ISO_8601
while parsing in the following manner:
SimpleDateFormat sdf = new SimpleDateFormat("YYYY-MM-DD'T'HH:MM:SS:MS");
Date date = null;
try {
date = sdf.parse("2018-01-30T23:59:59.000");
} catch (ParseException e) {
e.printStackTrace();
}
But It is throwing following exception:
java.text.ParseException: Unparseable date: "2018-01-30T23:59:59.000"
Any help is appreciated.
See the doc of SimpleDateFormat and try this:
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS");
LocalDateTime dateTime = LocalDateTime.parse("2018-01-30T23:59:59.000");
System.out.println(dateTime);
This prints:
2018-01-30T23:59:59
Your string is in ISO 8601 format. UTC or Coordinated Universal Time is not a format, it is a standard time used to define the time the rest of use in our respective time zones.
The date-time classes you were using, SimpleDateFormat and Date, are long outdated and the former in particular notoriously troublesome. I recommend that you instead use java.time, the modern Java date and time API. It is so much nicer to work with.
A LocalDateTime is a date with time of day and without time zone or offset from UTC. Its one-argument parse method parses ISO 8601, which is why no explicit formatter is needed.
What went wrong in your code
Your format pattern string has a number of issues to it. Which is one reason why you should appreciate the above solution without any explicit formatter. The first thing that goes wrong is: Your format pattern string has a colon, :, between seconds and milliseconds, whereas your date-time string has a dot, .. This is why you get the exception.
However, fixing this, your code yields the following Date:
Sun Dec 31 23:00:00 CET 2017
It’s one month off from the expected, and the minutes and seconds are missing. Because:
Uppercase YYYY is for week-based year and only useful with a week number. You need lowercase yyyy for year.
Uppercase DD is for day of year. You need lowercase dd for day of month.
You correctly used uppercase MM for month. Trying the same again for minutes won’t work. Maybe you can guess by now: it’s lowercase mm.
Not surprising you need lowercase ss for seconds.
UsingMS for milliseconds is interesting. SimpleDateFormat takes it as M for month (which we’ve already had twice before) and uppercase S for millisecond. Instead you needed uppercase SSS for the three digits of milliseconds.
Links
Oracle tutorial: Date Time explaining how to use java.time.
Wikipedia article: ISO 8601
Wikipedia article: Coordinated Universal Time on UTC
You need to escape the literal T:
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:SS");
See This SO Answer for more examples
Update: Your string is in the format
yyyy-MM-dd'T'HH:mm:ss.SSS
but you are trying to parse it with a completely uppercase format string.
This does not do what you want it to do and you should read the documentation on SimpleDateFormat and the format string placeholders

Confused with Converting the date with SimpleDateFormat [duplicate]

This question already has answers here:
How to convert "Mon Jun 18 00:00:00 IST 2012" to 18/06/2012?
(5 answers)
Closed 5 years ago.
I have a problem with date converting. I use the following program and I expect the output: 19.05.2017
But the output is: 05.00.2017
Can anybody help?
String t = "Fri May 19 00:00:00 CEST 2017";
Date d = new SimpleDateFormat("EEE MMM DD hh:mm:ss zzzz YYYY", Locale.US).parse(t);
String s = new SimpleDateFormat("dd.mm.yyyy").format(d).toString();
System.out.println(s);
A surprising result. The oldfashioned classes SimpleDateFormat and friends are full of surprises. This is meant as a negative thing.
Uppercase DD is day of year. Lowercase hh is hour of AM or PM (1 through 12). Uppercase YYYY is weekbased year (only useful with week number). So you are asking for a date that is a Friday in May and the 19th day of the year. Obviously this is not possible.
The result of parsing is Thu Jan 05 23:00:00 CET 2017. Apparently SimpleDateFormat opts for giving you a Friday and for using the zone offset of 2 hours implied by CEST even though the date it has chosen is not at the time of year where CEST (summer time) is in use. I don’t know whether it just gives you the first Friday of the weekbased year (Friday in week 1 of the year). Friday at 0000 hours at offset GMT+2 equals Thursday at 23 at GMT+1, which is CET.
Next for the formatting, 05 is the date as expected, but lowercase mm means minutes. Since the minutes are 0, you get 00. You got the right year.
Rather than using the outdated classes that give you such surprises, I agree with Sam’s answer that you should use the newer classes in java.time:
ZonedDateTime dt = ZonedDateTime.parse(t,
DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss zzz yyyy", Locale.US));
String s = dt.format(DateTimeFormatter.ofPattern("dd.MM.uuuu"));
This code gives you 19.05.2017 as you had expected. One of the good things about the modern classes is, if you try to parse with your original format pattern string, you will get a DateTimeParseException so you will know something is wrong. I certainly prefer an exception over incorrect output.
Another good thing is these classes respect the time zone in the input and use it in the output too (unless you explicitly instruct them otherwise). They will never turn Friday 6 January into Thursday 5 January because of some funny time zone issue.
Your input date is in Central European Summer Time and your date format is a bit wrong. Try
SimpleDateFormat input = new SimpleDateFormat("EEE MMM dd hh:mm:ss zzzz yyyy");
You might want to set the timezone on the output date format in order to get the date in the correct local time.
Ideally you'd move over to use a java.time style as shown here:
https://www.mkyong.com/java/java-convert-date-and-time-between-timezone/

Convert epoch to date with fractional seconds with Java [duplicate]

This question already has answers here:
How to include milliseconds in a formatted date string?
(3 answers)
Closed 5 years ago.
I have a date that I want to change into a different format.
Current format: Fri Apr 07 08:21:19 MDT 2017
Desired format: 2017-04-07T13:28:41.00MDT. I want to have the desired format output as a string.
I am currently doing this:
DateTimeFormatter sourceFormat = DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss z uuuu");
ZonedDateTime dateParsed = ZonedDateTime.parse(dateStr, sourceFormat);
String fullDateTimeStr = fullDateTime.format(dateParsed);
The formatting is correct, but the main issue I'm having is preserving the fractional seconds (the two numbers right before the time zone.) I know that the date I am receiving has the ms/fractional seconds preserved because when I print out long epoch = ((Date) date).getTime(); I get the epoch time and I can convert it (using an online conversion tool) and it shows the correct date/time with ms.
What's going on?
DateTimeFormatter targetFormat = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss.SSSz");
ZonedDateTime zdt = ZonedDateTime.now();
System.out.println(zdt.format(targetFormat));
Sample output:
2017-04-14T21:19:58.409CEST
You need SSS in the format pattern for the milliseconds.
Please consider whether you need the three or four letter time zone abbreviations that are often ambiguous. I would prefer to use DateTimeFormatter.ISO_ZONED_DATE_TIME for an output like 2017-04-14T21:22:49.344+02:00[Europe/Berlin]. This also saves you from building the pattern string yourself.

How do I convert the following String Date into Java Data format in Java?

How do i convert the following String Date into Data format in Java?
"10/01/2012 06:45:23:245946"
I am using the following code
dateFormat = new SimpleDateFormat("MM/dd/yyyy hh24:mm:ss:SSS");
java.util.Date parsedDate = dateFormat.parse("10/01/2012 06:45:23:245946");
And i am getting the following error
java.text.ParseException: Unparseable date: "10/01/2012 06:45:23:245946"
There is no hh24 in SimpleDateFormat, You should be using HH
Your pattern is wrong. Try:
"MM/dd/yyyy HH:mm:ss:SSS"
There is no hh24 in date matching pattern.
The pattern for hour is as follows:
H Hour in day (0-23) Number 0
k Hour in day (1-24) Number 24
See the whole date pattern on SimpleDateFormat javadoc.
You're almost there.
Get rid of the 24 after hh and change it to HH, that should make it work.
SimpleDateFormat dateFormat = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss:SSS");
Date parsedDate = dateFormat.parse("10/02/2012 06:45:23:245946");
System.out.println(parsedDate);
This will give you an error in time but parse the date successfull, as will all of our answers.
This is fixed by trimming the milliseconds down to 3 digits from 245946 to 245
If you do however want to use 6 digits I would suggest looking into the JodaTime API for more advanced datehandling as JodaTime handles microseconds. But as for java.util.Date, you're out of luck I'm afraid.
Read this bugreport why:
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4148168
EDIT: Thanks Jesper for pointing out my bad wording
The 24 in your date format is an invalid format specifier. Remove it. HH is the equivalent of hours on a 24-hour scale.
dateFormat = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss:SSS");

Categories

Resources