Code sample:
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z");
System.out.println(dateFormat.getTimeZone());
System.out.println(dateFormat.parse(time));
// dateFormat.setTimeZone(TimeZone.getTimeZone("Asia/Kolkata"));
I don't want to use the commented section.
Zone should be set based on IST that I am giving in the input string:
String time ="2018-04-06 16:13:00 IST";
Current machine zone is: America/New_York. How should I get zone changes to IST based on z?
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z");
String time ="2018-04-06 18:40:00 IST";
dateFormat.setTimeZone(TimeZone.getTimeZone("Asia/Kolkata"));
Above is running correctly but I don't want to set zone explicitly. It should be choosen based on IST I am giving in input time string.
"I don't want to set zone explicitly"
Sorry to disappoint you, but that's not possible with SimpleDateFormat. Timezone abbreviations like IST are ambiguous - as already said in the comments, IST is used in many places (AFAIK, in India, Ireland and Israel).
Some of those abbreviations might work sometimes, in specific cases, but usually in arbitrary and undocumented ways, and you can't really rely on that. Quoting the javadoc:
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 because the same abbreviation is often used for multiple time zones (for example, "CST" could be U.S. "Central Standard Time" and "China Standard Time"), and the Java platform can then only recognize one of them.
Due to the ambiguous and non-standard characteristics of timezones abbreviations, the only way to solve it with SimpleDateFormat is to set a specific timezone on it.
"It should be set to based on Z"
I'm not really sure what this means, but anyway...
Z is the UTC designator. But if the input contains a timezone short-name such as IST, well, it means that it's not in UTC, so you can't parse it as if it was in UTC.
If you want to output the date with Z, then you need another formatter set to UTC:
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z");
String time = "2018-04-06 18:40:00 IST";
dateFormat.setTimeZone(TimeZone.getTimeZone("Asia/Kolkata"));
// parse the input
Date date = dateFormat.parse(time);
// output format, use UTC
SimpleDateFormat outputFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ssX");
outputFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
System.out.println(outputFormat.format(date)); // 2018-04-06 13:10:00Z
Perhaps if you specify exactly the output you're getting (with actual values, some examples of outputs) and what's the expected output, we can help you more.
DateTimeFormatter formatter
= DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss z", Locale.ENGLISH);
String time ="2018-04-06 16:13:00 IST";
ZonedDateTime dateTime = ZonedDateTime.parse(time, formatter);
System.out.println(dateTime.getZone());
On my Java 8 this printed
Asia/Jerusalem
So apparently IST was interpreted as Israel Standard Time. On other computers with other settings you will instead get for instance Europe/Dublin for Irish Summer Time or Asia/Kolkata for India Standard Time. In any case the time zone comes from the abbreviation matching the pattern letter (lowercase) z in the format pattern string, which I suppose was what you meant(?)
If you want to control the choice of time zone in the all too frequent case of ambiguity, you may build your formatter in this way (idea stolen from this answer):
DateTimeFormatter formatter = new DateTimeFormatterBuilder()
.appendPattern("uuuu-MM-dd HH:mm:ss ")
.appendZoneText(TextStyle.SHORT,
Collections.singleton(ZoneId.of("Asia/Kolkata")))
.toFormatter(Locale.ENGLISH);
Now the output is
Asia/Kolkata
I am using and recommending java.time over the long outdated and notoriously troublesome SimpleDateFormat class.
Link: Oracle tutorial: Date Time explaining how to use java.time.
I try to convert from Milliseconds to string of date. However, the result is not correct as my expected.
The input is milliseconds (Ex: 1508206600485)
My time zone is UTC +10:00
------Expected-------------------------------------------- Actual------
01:32 (PM) 17/10/2017--------------------------------02:32 (PM) 17/10/2017
Here is the method of that
public static String getDate(long milliSeconds) {
SimpleDateFormat formatter = new SimpleDateFormat("hh:mm dd/MM/yyyy");
String dateString = formatter.format(new Date(milliSeconds));
return dateString;
}
Good you found a solution, I just like to add an approach with Java 8 new java.time API. The old classes (Date, Calendar and SimpleDateFormat) have lots of problems and design issues, and it's strongly recommended to switch to the new API if possible.
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, you'll also need 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.
To convert the millis value to a specific timezone, you can use the Instant class, then use a ZoneId to convert to a timezone, creating a ZonedDateTime.
Then you use a DateTimeFormatter to format it:
// convert millis value to a timezone
Instant instant = Instant.ofEpochMilli(1508206600485L);
ZonedDateTime z = instant.atZone(ZoneId.of("Australia/Sydney"));
// format it
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("hh:mm dd/MM/yyyy");
System.out.println(fmt.format(z)); // 01:16 17/10/2017
The output is:
01:16 17/10/2017
Note that I used hh for the hours. According to javadoc, this lettern represents the clock-hour-of-am-pm field (values from 1 to 12), so without the AM/PM indicator, it can be ambiguous. Maybe you want to add AM/PM field (adding the letter a to the format pattern), or change the hours to HH (hour-of-day, with values from 0 to 23).
Also note that the actual value of the ZonedDateTime is 2017-10-17T13:16:40.485+11:00 (01:16 PM), because in October 17th 2017, Sydney is in Daylight Saving Time, so the actual offset is +11:00.
Basing on #phlaxyr, I have solved my problem. You can get your time zone in this link below
http://tutorials.jenkov.com/java-date-time/java-util-timezone.html
public static String getDate(long milliSeconds) {
SimpleDateFormat formatter = new SimpleDateFormat("hh:mm dd/MM/yyyy");
formatter.setTimeZone(TimeZone.getTimeZone("Australia/Sydney"));
String dateString = formatter.format(new Date(milliSeconds));
return dateString;
}
Java 8 added a new java.time API for working with dates and times (JSR 310).
I have date and time as string (e.g., "2014-04-08 12:30"). How can I obtain a LocalDateTime instance from the given string?
After I finished working with the LocalDateTime object: How can I then convert the LocalDateTime instance back to a string with the same format as shown above?
Parsing date and time
To create a LocalDateTime object from a string you can use the static LocalDateTime.parse() method. It takes a string and a DateTimeFormatter as parameter. The DateTimeFormatter is used to specify the date/time pattern.
String str = "1986-04-08 12:30";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
LocalDateTime dateTime = LocalDateTime.parse(str, formatter);
Formatting date and time
To create a formatted string out a LocalDateTime object you can use the format() method.
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
LocalDateTime dateTime = LocalDateTime.of(1986, Month.APRIL, 8, 12, 30);
String formattedDateTime = dateTime.format(formatter); // "1986-04-08 12:30"
Note that there are some commonly used date/time formats predefined as constants in DateTimeFormatter. For example: Using DateTimeFormatter.ISO_DATE_TIME to format the LocalDateTime instance from above would result in the string "1986-04-08T12:30:00".
The parse() and format() methods are available for all date/time related objects (e.g. LocalDate or ZonedDateTime)
You can also use LocalDate.parse() or LocalDateTime.parse() on a String without providing it with a pattern, if the String is in ISO 8601 format.
For example,
String strDate = "2015-08-04";
LocalDate aLD = LocalDate.parse(strDate);
System.out.println("Date: " + aLD);
String strDatewithTime = "2015-08-04T10:11:30";
LocalDateTime aLDT = LocalDateTime.parse(strDatewithTime);
System.out.println("Date with Time: " + aLDT);
Output,
Date: 2015-08-04
Date with Time: 2015-08-04T10:11:30
And use DateTimeFormatter only if you have to deal with other date patterns.
For instance, in the following example, dd MMM uuuu represents the day of the month (two digits), three letters of the name of the month (Jan, Feb, Mar,...), and a four-digit year:
DateTimeFormatter dTF = DateTimeFormatter.ofPattern("dd MMM uuuu");
String anotherDate = "04 Aug 2015";
LocalDate lds = LocalDate.parse(anotherDate, dTF);
System.out.println(anotherDate + " parses to " + lds);
Output
04 Aug 2015 parses to 2015-08-04
also remember that the DateTimeFormatter object is bidirectional; it can both parse input and format output.
String strDate = "2015-08-04";
LocalDate aLD = LocalDate.parse(strDate);
DateTimeFormatter dTF = DateTimeFormatter.ofPattern("dd MMM uuuu");
System.out.println(aLD + " formats as " + dTF.format(aLD));
Output
2015-08-04 formats as 04 Aug 2015
(See complete list of Patterns for Formatting and Parsing DateFormatter.)
Symbol Meaning Presentation Examples
------ ------- ------------ -------
G era text AD; Anno Domini; A
u year year 2004; 04
y year-of-era year 2004; 04
D day-of-year number 189
M/L month-of-year number/text 7; 07; Jul; July; J
d day-of-month number 10
Q/q quarter-of-year number/text 3; 03; Q3; 3rd quarter
Y week-based-year year 1996; 96
w week-of-week-based-year number 27
W week-of-month number 4
E day-of-week text Tue; Tuesday; T
e/c localized day-of-week number/text 2; 02; Tue; Tuesday; T
F week-of-month number 3
a am-pm-of-day text PM
h clock-hour-of-am-pm (1-12) number 12
K hour-of-am-pm (0-11) number 0
k clock-hour-of-am-pm (1-24) number 0
H hour-of-day (0-23) number 0
m minute-of-hour number 30
s second-of-minute number 55
S fraction-of-second fraction 978
A milli-of-day number 1234
n nano-of-second number 987654321
N nano-of-day number 1234000000
V time-zone ID zone-id America/Los_Angeles; Z; -08:30
z time-zone name zone-name Pacific Standard Time; PST
O localized zone-offset offset-O GMT+8; GMT+08:00; UTC-08:00;
X zone-offset 'Z' for zero offset-X Z; -08; -0830; -08:30; -083015; -08:30:15;
x zone-offset offset-x +0000; -08; -0830; -08:30; -083015; -08:30:15;
Z zone-offset offset-Z +0000; -0800; -08:00;
p pad next pad modifier 1
' escape for text delimiter
'' single quote literal '
[ optional section start
] optional section end
# reserved for future use
{ reserved for future use
} reserved for future use
Both Sufiyan Ghori's and micha's answer explain very well the question regarding string patterns. However, just in case you are working with ISO 8601, there isn't any need to apply DateTimeFormatter since LocalDateTime is already prepared for it:
Convert a LocalDateTime to a Time Zone ISO 8601 String
LocalDateTime ldt = LocalDateTime.now();
ZonedDateTime zdt = ldt.atZone(ZoneOffset.UTC); // You might use a different zone
String iso8601 = zdt.toString();
Convert from ISO8601 String back to a LocalDateTime
String iso8601 = "2016-02-14T18:32:04.150Z";
ZonedDateTime zdt = ZonedDateTime.parse(iso8601);
LocalDateTime ldt = zdt.toLocalDateTime();
Parsing a string with date and time into a particular point in time (Java calls it an "Instant") is quite complicated. Java has been tackling this in several iterations. The latest one, java.time and java.time.chrono, covers almost all needs (except time dilation :) ).
However, that complexity brings a lot of confusion.
The key to understand date parsing is:
Why does Java have so many ways to parse a date?
There are several systems to measure a time. For instance, the historical Japanese calendars were derived from the time ranges of the reign of the respective emperor or dynasty. Then there is, e.g., the Unix timestamp.
Fortunately, the whole (business) world managed to use the same.
Historically, the systems were being switched from/to, for various reasons. E.g., from the Julian calendar to the Gregorian calendar in 1582; so, the 'western' dates before that need to be treated differently.
And, of course, the change did not happen at once. Because the calendar came from the headquarters of some religion and other parts of Europe believed in other deities, for instance Germany did not switch until the year 1700.
...and why is the LocalDateTime, ZonedDateTime et al. so complicated
There are time zones.
A time zone is basically a "stripe"*[3] of the Earth's surface whose authorities follow the same rules of when does it have which time offset. This includes summer time rules.
The time zones change over time for various areas, mostly based on who conquers whom. And one time zone's rules change over time as well.
There are time offsets. That is not the same as time zones, because a time zone may be, e.g., "Prague", but that has summer time offset and winter time offset.
If you get a timestamp with a time zone, the offset may vary, depending on what part of the year it is in. During the leap hour, the timestamp may mean two different times, so without additional information, it can't be reliably converted.
Note: By timestamp I mean "a string that contains a date and/or time, optionally with a time zone and/or time offset."
Several time zones may share the same time offset for certain periods. For instance, the GMT/UTC time zone is the same as the "London" time zone when the summer time offset is not in effect.
To make it a bit more complicated (but that's not too important for your use case):
The scientists observe Earth's dynamic, which changes over time; based on that, they add seconds at the end of individual years. (So 2040-12-31 24:00:00 may be a valid date-time.) This needs regular updates of the metadata that systems use to have the date conversions right. E.g., on Linux, you get regular updates to the Java packages including these new data.
The updates do not always keep the previous behavior for both historical and future timestamps. So it may happen that parsing of the two timestamps around some time zone's change comparing them may give different results when running on different versions of the software. That also applies to comparing between the affected time zone and other time zone.
Should this cause a bug in your software, consider using some timestamp that does not have such complicated rules, like Unix timestamp.
Because of 7, for the future dates, we can't convert dates exactly with certainty. So, for instance, current parsing of 8524-02-17 12:00:00 may be off a couple of seconds from the future parsing.
JDK's APIs for this evolved with the contemporary needs
The early Java releases had just java.util.Date which had a bit naive approach, assuming that there's just the year, month, day, and time. This quickly did not suffice.
Also, the needs of the databases were different, so quite early, java.sql.Date was introduced, with its own limitations.
Because neither covered different calendars and time zones well, the Calendar API was introduced.
This still did not cover the complexity of the time zones. And yet, the mix of the above APIs was really a pain to work with. So as Java developers started working on global web applications, libraries that targeted most use cases, like JodaTime, got quickly popular. JodaTime was the de facto standard for about a decade.
But the JDK did not integrate with JodaTime, so working with it was a bit cumbersome. So, after a very long discussion on how to approach the matter, JSR-310 was created mainly based on JodaTime.
How to deal with it in Java's java.time
Determine what type to parse a timestamp to
When you are consuming a timestamp string, you need to know what information it contains. This is the crucial point. If you don't get this right, you end up with a cryptic exceptions like "Can't create Instant", "Zone offset missing", "unknown zone id", etc.
Unable to obtain OffsetDateTime from TemporalAccessor
Unable to obtain ZonedDateTime from TemporalAccessor
Unable to obtain LocalDateTime from TemporalAccessor
Unable to obtain Instant from TemporalAccessor
Does it contain the date and the time?
Does it have a time offset?
A time offset is the +hh:mm part. Sometimes, +00:00 may be substituted with Z as 'Zulu time', UTC as Universal Time Coordinated, or GMT as Greenwich Mean Time. These also set the time zone.
For these timestamps, you use OffsetDateTime.
Does it have a time zone?
For these timestamps, you use ZonedDateTime.
Zone is specified either by
name ("Prague", "Pacific Standard Time", "PST"), or
"zone ID" ("America/Los_Angeles", "Europe/London"), represented by java.time.ZoneId.
The list of time zones is compiled by a "TZ database", backed by ICAAN.
According to ZoneId's javadoc, the zone id's can also somehow be specified as Z and offset. I'm not sure how this maps to real zones.
If the timestamp, which only has a TZ, falls into a leap hour of time offset change, then it is ambiguous, and the interpretation is subject of ResolverStyle, see below.
If it has neither, then the missing context is assumed or neglected. And the consumer has to decide. So it needs to be parsed as LocalDateTime and converted to OffsetDateTime by adding the missing info:
You can assume that it is a UTC time. Add the UTC offset of 0 hours.
You can assume that it is a time of the place where the conversion is happening. Convert it by adding the system's time zone.
You can neglect and just use it as is. That is useful e.g. to compare or subtract two times (see Duration), or when you don't know and it doesn't really matter (e.g., local bus schedule).
Partial time information
Based on what the timestamp contains, you can take LocalDate, LocalTime, OffsetTime, MonthDay, Year, or YearMonth out of it.
If you have the full information, you can get a java.time.Instant. This is also internally used to convert between OffsetDateTime and ZonedDateTime.
Figure out how to parse it
There is an extensive documentation on DateTimeFormatter which can both parse a timestamp string and format to string.
The pre-created DateTimeFormatters should cover more or less all standard timestamp formats. For instance, ISO_INSTANT can parse 2011-12-03T10:15:30.123457Z.
If you have some special format, then you can create your own DateTimeFormatter (which is also a parser).
private static final DateTimeFormatter TIMESTAMP_PARSER = new DateTimeFormatterBuilder()
.parseCaseInsensitive()
.append(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SX"))
.toFormatter();
I recommend to look at the source code of DateTimeFormatter and get inspired on how to build one using DateTimeFormatterBuilder. While you're there, also have a look at ResolverStyle which controls whether the parser is LENIENT, SMART or STRICT for the formats and ambiguous information.
TemporalAccessor
Now, the frequent mistake is to go into the complexity of TemporalAccessor. This comes from how the developers were used to work with SimpleDateFormatter.parse(String). Right, DateTimeFormatter.parse("...") gives you TemporalAccessor.
// No need for this!
TemporalAccessor ta = TIMESTAMP_PARSER.parse("2011-... etc");
But, equipped with the knowledge from the previous section, you can conveniently parse into the type you need:
OffsetDateTime myTimestamp = OffsetDateTime.parse("2011-12-03T10:15:30.123457Z", TIMESTAMP_PARSER);
You do not actually need to the DateTimeFormatter either. The types you want to parse have the parse(String) methods.
OffsetDateTime myTimestamp = OffsetDateTime.parse("2011-12-03T10:15:30.123457Z");
Regarding TemporalAccessor, you can use it if you have a vague idea of what information there is in the string, and want to decide at runtime.
I hope I shed some light of understanding onto your soul :)
Note: There's a backport of java.time to Java 6 and 7: ThreeTen-Backport. For Android it has ThreeTenABP.
[3] Not just that they are not stripes, but there also some weird extremes. For instance, some neighboring Pacific Islands have +14:00 and -11:00 time zones. That means, that while on one island, there is 1st May 3 PM, on another island not so far, it is still 30 April 12 PM (if I counted correctly :) )
Another thing to note with LocalDateTime.parse is that you cannot use it with a custom formatter with only date formatter characters, such as uuuuMMdd. In this case, you should use LocalDate.parse instead. For example:
String s = "20210223";
// ok
LocalDate.parse(s, DateTimeFormatter.ofPattern("uuuuMMdd"));
// java.time.format.DateTimeParseException
LocalDateTime.parse(s, DateTimeFormatter.ofPattern("uuuuMMdd"));
Get the current UTC time in the required format
// Current the UTC time
OffsetDateTime utc = OffsetDateTime.now(ZoneOffset.UTC);
// Get LocalDateTime
LocalDateTime localDateTime = utc.toLocalDateTime();
System.out.println("*************" + localDateTime);
// Formatted UTC time
DateTimeFormatter dTF = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
System.out.println(" formats as " + dTF.format(localDateTime));
// Get the UTC time for the current date
Date now = new Date();
LocalDateTime utcDateTimeForCurrentDateTime = Instant.ofEpochMilli(now.getTime()).atZone(ZoneId.of("UTC")).toLocalDateTime();
DateTimeFormatter dTF2 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
System.out.println(" formats as " + dTF2.format(utcDateTimeForCurrentDateTime));
All the answers are good. The Java 8+ versions have these patterns for parsing and formatting time zones: V, z, O, X, x, Z.
Here's they are, for parsing, according to rules from the documentation:
Symbol Meaning Presentation Examples
------ ------- ------------ -------
V time-zone ID zone-id America/Los_Angeles; Z; -08:30
z time-zone name zone-name Pacific Standard Time; PST
O localized zone-offset offset-O GMT+8; GMT+08:00; UTC-08:00;
X zone-offset 'Z' for zero offset-X Z; -08; -0830; -08:30; -083015; -08:30:15;
x zone-offset offset-x +0000; -08; -0830; -08:30; -083015; -08:30:15;
Z zone-offset offset-Z +0000; -0800; -08:00;
But how about formatting?
Here's a sample for a date (assuming ZonedDateTime) that show these patters behavior for different formatting patters:
// The helper function:
static void printInPattern(ZonedDateTime dt, String pattern) {
System.out.println(pattern + ": " + dt.format(DateTimeFormatter.ofPattern(pattern)));
}
// The date:
String strDate = "2020-11-03 16:40:44 America/Los_Angeles";
DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss zzzz");
ZonedDateTime dt = ZonedDateTime.parse(strDate, format);
// 2020-11-03T16:40:44-08:00[America/Los_Angeles]
// Rules:
// printInPattern(dt, "V"); // exception!
printInPattern(dt, "VV"); // America/Los_Angeles
// printInPattern(dt, "VVV"); // exception!
// printInPattern(dt, "VVVV"); // exception!
printInPattern(dt, "z"); // PST
printInPattern(dt, "zz"); // PST
printInPattern(dt, "zzz"); // PST
printInPattern(dt, "zzzz"); // Pacific Standard Time
printInPattern(dt, "O"); // GMT-8
// printInPattern(dt, "OO"); // exception!
// printInPattern(dt, "OO0"); // exception!
printInPattern(dt, "OOOO"); // GMT-08:00
printInPattern(dt, "X"); // -08
printInPattern(dt, "XX"); // -0800
printInPattern(dt, "XXX"); // -08:00
printInPattern(dt, "XXXX"); // -0800
printInPattern(dt, "XXXXX"); // -08:00
printInPattern(dt, "x"); // -08
printInPattern(dt, "xx"); // -0800
printInPattern(dt, "xxx"); // -08:00
printInPattern(dt, "xxxx"); // -0800
printInPattern(dt, "xxxxx"); // -08:00
printInPattern(dt, "Z"); // -0800
printInPattern(dt, "ZZ"); // -0800
printInPattern(dt, "ZZZ"); // -0800
printInPattern(dt, "ZZZZ"); // GMT-08:00
printInPattern(dt, "ZZZZZ"); // -08:00
In the case of positive offset, the + sign character is used everywhere (where there is - now) and never omitted.
This well works for new java.time types. If you're about to use these for java.util.Date or java.util.Calendar - not all going to work as those types are broken (and so marked as deprecated, please don't use them).
Let's take two questions, example string "2014-04-08 12:30"
How can I obtain a LocalDateTime instance from the given string?
import java.time.format.DateTimeFormatter
import java.time.LocalDateTime
final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")
// Parsing or conversion
final LocalDateTime dt = LocalDateTime.parse("2014-04-08 12:30", formatter)
dt should allow you to all date-time related operations
How can I then convert the LocalDateTime instance back to a string with the same format?
final String date = dt.format(formatter)
The universal method looks as below. It works for:
yyyy-MM-dd HH:mm:ss.SSS
yyyy-MM-dd HH:mm:ss.S
yyyy-MM-dd HH:mm:ss
yyyy-MM-dd HH:mm
yyyy-MM-dd HH
yyyy-MM-dd
public static final String DATE_FORMAT_YYYY_MM_DD_HH_MM_SS_SSS = "yyyy-MM-dd HH:mm:ss.SSS";
public LocalDateTime stringToLocalDateTime(String s){
return LocalDateTime.parse(s, DateTimeFormatter.ofPattern(DATE_FORMAT_YYYY_MM_DD_HH_MM_SS_SSS.substring(0, s.length())));
}
I found it wonderful to cover multiple variants of date time formats like this:
final DateTimeFormatterBuilder dtfb = new DateTimeFormatterBuilder();
dtfb.appendOptional(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSSSSSSS"))
.appendOptional(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSSSSSS"))
.appendOptional(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSSSSS"))
.appendOptional(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSSSS"))
.appendOptional(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSSS"))
.appendOptional(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSS"))
.appendOptional(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS"))
.appendOptional(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SS"))
.appendOptional(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.S"))
.parseDefaulting(ChronoField.HOUR_OF_DAY, 0)
.parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0)
.parseDefaulting(ChronoField.SECOND_OF_MINUTE, 0);
There are already many good answers to this question. This answer shows how to use predefined DateTimeFormatters to build a DateTimeFormatter which can parse the given date-time string.
However, formatting the obtained LocalDateTime using this DateTimeFormatter will return a string with time in HH:mm:ss format. To restrict the time string to HH:mm format, we still have to use the pattern uuuu-MM-dd HH:mm as other answers have done.
Demo:
class Main {
public static void main(String[] args) {
DateTimeFormatter dtf = new DateTimeFormatterBuilder()
.append(DateTimeFormatter.ISO_LOCAL_DATE)
.appendLiteral(' ')
.append(DateTimeFormatter.ISO_LOCAL_TIME)
.toFormatter(Locale.ENGLISH);
String strDateTime = "2014-04-08 12:30";
LocalDateTime ldt = LocalDateTime.parse(strDateTime, dtf);
System.out.println(ldt);
// However, formatting the obtained LocalDateTime using this DateTimeFormatter
// will return a string with time in HH:mm:ss format. To restrict the time
// string to HH:mm format, we still have to use the pattern, uuuu-MM-dd HH:mm as
// other answers have done.
String strDateTimeFormatted = ldt.format(dtf);
System.out.println(strDateTimeFormatted);
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm", Locale.ENGLISH);
strDateTimeFormatted = ldt.format(formatter);
System.out.println(strDateTimeFormatted);
}
}
Output:
2014-04-08T12:30
2014-04-08 12:30:00
2014-04-08 12:30
ONLINE DEMO
Note: Here, you can use y instead of u but I prefer u to y.
Learn more about the modern Date-Time API from Trail: Date Time.
I need to extract the date field from DB and store it in a VO. How can I compare the hours difference from two dates.
For ex:
Let's say date1 = 01-SEP-17 10:00:00 and date2 = 05-SEP-17 12:00:00. I need to compare the two dates and perform some operations like:
if(hours>10){
//do something
}
if(hours<10){
//do something else
}
I'm just able to calculate the difference between the hours (date2-date1) as 2 but how to consider the date too while calculating the difference between the hours?
My present code:
Date dateA = someVO.getDate();
long date = System.currentTimeMillis();
SimpleDateFormat df = new SimpleDateFormat("dd-MM-YY HH:mm:ss");
Date date1 = new Date(date);
Date date2 = df.parse(dateA.toString());
long date1Hours = date1.getHours();
long date2Hours = date2.getHours();
long dateDiff = date1Hours-date2Hours;
if(dateDiff>10){
//something
}
else if(dateDiff<10){
//something else
}
Easy enough to do using the new Java-Time API added in Java 8:
DateTimeFormatter fmt = new DateTimeFormatterBuilder()
.parseCaseInsensitive()
.appendPattern("dd-MMM-yy HH:mm:ss")
.toFormatter(Locale.US);
LocalDateTime date1 = LocalDateTime.parse("01-SEP-17 10:00:00", fmt);
LocalDateTime date2 = LocalDateTime.parse("05-SEP-17 12:00:00", fmt);
long hours = ChronoUnit.HOURS.between(date1, date2);
System.out.println(hours);
Output
98
First you need to change the pattern used in SimpleDateFormat, and also use a java.util.Locale to specify that the month name is in English (otherwise it uses the system default locale, and it's not guaranteed to always be English).
Then you get the correspondent millis value of each Date, calculate the difference between them and convert this to hours, using a java.util.concurrent.TimeUnit:
SimpleDateFormat df = new SimpleDateFormat("dd-MMM-yy HH:mm:ss", Locale.ENGLISH);
Date date1 = df.parse("01-SEP-17 10:00:00");
Date date2 = df.parse("05-SEP-17 12:00:00");
// get the difference in hours
long dateDiff = TimeUnit.MILLISECONDS.toHours(date2.getTime() - date1.getTime());
dateDiff will be 98.
If you want to compare with the current date, just use new Date().
Daylight Saving Time issues
There's one problem with this approach. Although it doesn't make a difference for most part of the year, there can be differences due to Daylight Saving Time changes.
By default, SimpleDateFormat uses the JVM default timezone. If between the 2 dates there's a Daylight Saving Time changeover (or just an offset change), the result might be different.
Example: in Africa/Windhoek timezone, in September 3rd 2017, at 2 AM, clocks shifted 1 hour forward, from 2 AM to 3 AM (and the offset changed from +01:00 to +02:00). This means that, at that day, all local times between 2 AM and 2:59 AM don't exist in this timezone (it's like they "skipped" this hour).
So, if the JVM default timezone is Africa/Windhoek, then the difference using the code above will be 97 hours (and not 98).
Even if your JVM default timezone is not Africa/Windhoek, this can still happen, depending on the timezone and the dates involved.
Not only that, but the default timezone can be changed without notice, even at runtime. It's always better to specify which timezone you're working with instead of just relying on the default.
You can't avoid DST effects (unless you use UTC), but at least you can choose which timezone you're going to use instead of relying on the system default (that can be changed without notice).
It's possible to set a timezone in the formatter, so all dates will be parsed taking this timezone into account. In the example below, I'm using Europe/London, but of course you can change to one that best suits your case:
// set Europe/London timezone in the SimpleDateFormat
df.setTimeZone(TimeZone.getTimeZone("Europe/London"));
Now all the parsed dates will be considered to be in London timezone (but remind that DST effects will still be considered - the advantage is that you know what timezone you're using and any changes in the JVM's default won't make your code suddenly start giving different and unexpected results).
Always use IANA timezones names (always in the format Continent/City, like America/Sao_Paulo or Europe/Berlin).
Avoid using the 3-letter abbreviations (like CST or PST) because they are ambiguous and not standard.
You can get a list of all timezones using TimeZone.getAvailableIDs() - then you can choose the one that best suits your case.
If you don't want to consider DST effects, you can use TimeZone.getTimeZone("UTC") - because UTC is a standard without DST changes.
Java new Date/Time API
The old classes (Date, Calendar and SimpleDateFormat) have lots of problems and design issues, and they're being replaced by the new APIs.
If you're using Java 8, consider using the new java.time API. It's easier, less bugged and less error-prone than the old APIs.
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.
First you need to parse the inputs (using a DateTimeFormatter) and specify in what timezone they are. As the dates also have a timezone, I'm using a ZonedDateTime, which is the best choice for this case.
Then you can easily calculate the difference in hours using a ChronoUnit. In the example below, I'm also using London timezone as an example:
DateTimeFormatter fmt = new DateTimeFormatterBuilder()
// case insensitive for month name in all caps
.parseCaseInsensitive()
// date/time pattern
.appendPattern("dd-MMM-yy HH:mm:ss")
// use English locale for month name
.toFormatter(Locale.ENGLISH)
// set a timezone
.withZone(ZoneId.of("Europe/London"));
// parse the dates
ZonedDateTime z1 = ZonedDateTime.parse("01-SEP-17 10:00:00", fmt);
ZonedDateTime z2 = ZonedDateTime.parse("05-SEP-17 12:00:00", fmt);
// calculate the difference in hours
long diffHours = ChronoUnit.HOURS.between(z1, z2);
If you want to use UTC, just change the ZoneId to ZoneOffset.UTC constant. If you want to compare with the current date, just use:
// use the same ZoneId used in the formatter if you want to consider DST effects
ZonedDateTime.now(ZoneId.of("Europe/London"));
Conversions to/from Date
If you still need to work with java.util.Date, it's possible to convert from/to the new API. In Java 8 you can use native methods, and in Java <=7 the ThreeTen Backport has the org.threeten.bp.DateTimeUtils class.
To convert a Date to the new classes:
Date date = // java.util.Date
// convert to zoneddatetime (java 8)
ZonedDateTime z = date.toInstant().atZone(ZoneId.of("Europe/London"));
// convert to zoneddatetime (java 7 ThreeTen Backport)
ZonedDateTime z = DateTimeUtils.toInstant(date).atZone(ZoneId.of("Europe/London"));
To convert a ZonedDateTime back to a date:
// convert to zoneddatetime (java 8)
Date date = Date.from(z.toInstant());
// convert to zoneddatetime (java 7 ThreeTen Backport)
Date date = DateTimeUtils.toDate(z.toInstant());
You've essentially already got the times in milliseconds. You could always just compare the milliseconds directly instead.
long tenHoursInMillis = 36000000;
long dateVOMillis = someVO.getDate().getTime();
long dateSysMillis = System.currentTimeMillis();
if(dateSysMillis - dateAMillis > tenHoursInMillis) {
// do something
}
else if(dateSysMillis - dateAMillis < tenHoursInMillis) {
// do something else
}
// do something when they're equal
This question already has answers here:
Convert a date format in epoch
(6 answers)
Closed 5 years ago.
I am very new to Java and coding in general - I have some code which returns a timestamp in the following format yyyy.MM.dd HH:mm:ss:ms which is shown below:
SimpleDateFormat formatter = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss:sss");
This returns:
2017.07.19 11:42:30:423
Is there a way to edit the "SimpleDateFormat formatter" code above to return the date/time as an epoch timestamp that includes milliseconds so that the value returned is formatted as per the below?
1500464550423
I'm hoping that I can amend the ("yyyy.MM.dd HH:mm:ss:sss") part of the SimpleDateFormat formatter code to do this.
Any help or advice is much appreciated.
Thanks
You have a simple error in the use of case in your format pattern string (these are case sensitive). And worse, you are using the old and troublesome SimpleDateFormat class. One of the many problems with it is it’s not telling you what the problem is.
So I recommend you use the modern Java date and time API instead (I am deliberately using your format pattern string verbatim):
String receivedTimetamp = "2017.07.19 11:42:30:423";
DateTimeFormatter parseFormatter
= DateTimeFormatter.ofPattern("yyyy.MM.dd HH:mm:ss:sss");
LocalDateTime dateTime = LocalDateTime.parse(receivedTimetamp, parseFormatter);
System.out.println(dateTime);
This code throws an IllegalArgumentException: Too many pattern letters: s. I hope this calls your awareness to the fact that you are using two s’s for seconds and three s’s for fraction of second. If it still isn’t clear, the documentation will tell you that lowercase s is correct for seconds, while you need uppercase S for the fraction. Let’s repair:
DateTimeFormatter parseFormatter
= DateTimeFormatter.ofPattern("yyyy.MM.dd HH:mm:ss:SSS");
Now the code prints 2017-07-19T11:42:30.423, so we have managed to parse the string correctly.
To convert to milliseconds we are still missing a crucial piece of information: in what time zone should the timestamp be interpreted? I think the two obvious guesses are UTC and your local time zone (which I don’t know). Try UTC:
System.out.println(dateTime.atOffset(ZoneOffset.UTC).toInstant().toEpochMilli());
This produces 1500464550423, which is the number you asked for. I suppose we’re done.
If you wanted your JVM’s time zone setting instead, use .atZone(ZoneId.systemDefault()) instead of .atOffset(ZoneOffset.UTC), but beware that the setting may be altered by other software running in the same JVM, so this is fragile.
First of all, check the documentation of SimpleDateFormat. The pattern that corresponds to milliseconds is an uppercase S, while the lowercase s corresponds to seconds. The problem is that SimpleDateFormat usually doesn't complain and try to parse 423 as seconds, adding this amount to your end date (giving an incorrect result).
Anyway, SimpleDateFormat just parses a String to a java.util.Date or formats the Date to a String. If you want the epoch millis value, you must get it from the Date object:
// input string
String s = "2017.07.19 11:42:30:423";
// use correct format ('S' for milliseconds)
SimpleDateFormat formatter = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss:SSS");
// parse to a date
Date date = formatter.parse(s);
// get epoch millis
long millis = date.getTime();
System.out.println(millis); // 1500475350423
The problem is that SimpleDateFormat uses the system's default timezone, so the final value above (1500475350423) will be equivalent to the specificed date and time in my system's timezone (which can be different from yours - just for the record, my system's default timezone is America/Sao_Paulo). If you want to specify in what timezone this date is, you need to set in the formatter (before calling parse):
// set a timezone to the formatter (using UTC as example)
formatter.setTimeZone(TimeZone.getTimeZone("UTC"));
With this, the result for millis will be 1500464550423 (the equivalent to the specificed date and time in UTC).
To do the opposite (create a date from the millis value), you must create a Date object and then pass it to the formatter (also taking care of setting a timezone to the formatter):
// create date from millis
Date date = new Date(1500464550423L);
// use correct format ('S' for milliseconds)
SimpleDateFormat formatter = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss:SSS");
formatter.setTimeZone(TimeZone.getTimeZone("UTC"));
// format date
String formatted = formatter.format(date);
Java new date/time API
The old classes (Date, Calendar and SimpleDateFormat) have lots of problems and design issues, and they're being replaced by the new APIs.
If you're using Java 8, consider using the new java.time API. It's easier, less bugged and less error-prone than the old APIs.
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.
As the input String has no timezone information (only date and time), first I parsed it to a LocalDateTime (a class that represents a date and time without timezone). Then I convert this date/time to a specific timezone and get the millis value from it:
// input string
String s = "2017.07.19 11:42:30:423";
// use correct format ('S' for milliseconds)
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy.MM.dd HH:mm:ss:SSS");
// as the input string has no timezone information, parse it to a LocalDateTime
LocalDateTime dt = LocalDateTime.parse(s, formatter);
// convert the LocalDateTime to a timezone
ZonedDateTime zdt = dt.atZone(ZoneId.of("Europe/London"));
// get the millis value
long millis = zdt.toInstant().toEpochMilli(); // 1500460950423
The value is now 1500460950423, equivalent to the specified date and time in London timezone.
Note that the 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 PST) because they are ambiguous and not standard.
You can get a list of available timezones (and choose the one that fits best your system) by calling ZoneId.getAvailableZoneIds().
You can also use ZoneOffset.UTC constant if you want to use UTC.
To do the opposite, you can get the millis value to create an Instant, convert it to a timezone and pass it to the formatter:
// create Instant from millis value
Instant instant = Instant.ofEpochMilli(1500460950423L);
// use correct format ('S' for milliseconds)
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy.MM.dd HH:mm:ss:SSS");
// convert to timezone
ZonedDateTime z = instant.atZone(ZoneId.of("Europe/London"));
// format
String formatted = z.format(formatter);
First advice is to move to java8 java.time API instead of learning the broken java.date API
then do:
Instant i = Instant.now();
System.out.println(i.toEpochMilli());
in your case you can do:
LocalDateTime myldt = LocalDateTime.parse("2017-06-14 14:29:04",
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
System.out.println(myldt.toInstant(ZoneOffset.UTC).toEpochMilli());
note that as soon as you play more with the api you will find more ways to achieve the same thing, at the end you will end invoking toEpochMilli
String strDate = "Jun 13 2003 23:11:52.454 UTC";
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("MMM dd yyyy HH:mm:ss.SSS zzz");
ZonedDateTime zdt = ZonedDateTime.parse(strDate,dtf);
System.out.println(zdt.toInstant().toEpochMilli()); // 1055545912454
You can try
long time = System.currentTimeMillis();
If you have a java.util.Date then invoking getTime() will return the number of millis since the epoch. For example:
SimpleDateFormat formatter = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss:sss");
Date dateToBeFormatted = new Date();
// this will print a datetime literal on the above format
System.out.println(formatter.format(dateToBeFormatted));
// this will print the number of millis since the Java epoch
System.out.println(dateToBeFormatted.getTime());
The key point here is that in order to get the number of millis since the epoch you do not need a SimpleDateFormatter because the number of millis since the epoch is a property of the Date.