This question already has answers here:
Why is string to date and back to string resulting in two different strings?
(2 answers)
Closed 1 year ago.
I am using the following code to get the date in ISO-8601 format. For UTC the value returned does not contain offset.
OffsetDateTime dateTime = OffsetDateTime.ofInstant(
Instant.ofEpochMilli(epochInMilliSec), zoneId);
return dateTime.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME);
For other time formats the response returned looks like:
2016-10-30T17:00:00-07:00
In case of UTC the value returned is:
2016-10-30T17:00:00Z
I want it to be:
2016-10-30T17:00:00+00:00
Note: Do not use UTC-0 as -00:00 is not ISO8601 compliant.
The built-in formatter uses Z when the offset is zero. The Z is short for Zulu and means UTC.
You'll have to use a custom formatter, using a java.time.format.DateTimeFormatterBuilder to set a custom text for when the offset is zero:
DateTimeFormatter fmt = new DateTimeFormatterBuilder()
// date and time, use built-in
.append(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
// append offset, set "-00:00" when offset is zero
.appendOffset("+HH:MM", "-00:00")
// create formatter
.toFormatter();
System.out.println(dateTime.format(fmt));
This will print:
2016-10-30T17:00:00-00:00
Just reminding that -00:00 is not ISO8601 compliant. The standard allows only Z and +00:00 (and the variations +0000 and +00) when the offset is zero.
If you want +00:00, just change the code above to:
DateTimeFormatter fmt = new DateTimeFormatterBuilder()
// date and time, use built-in
.append(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
// append offset
.appendPattern("xxx")
// create formatter
.toFormatter();
This formatter will produce the output:
2016-10-30T17:00:00+00:00
If you can accept +00:00 instead of -00:00, you can also use a simpler DateTimeFormatter:
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ssxxx");
OffsetDateTime odt = OffsetDateTime.parse("2016-10-30T17:00:00Z");
System.out.println(fmt.format(odt));
I used x whereas the standard toString() method of OffsetDateTime uses X. The main difference between x and X is that one return +00:00 vs. Z for the other.
Related
This question already has answers here:
Cannot parse String in ISO 8601 format, lacking colon in offset, to Java 8 Date
(3 answers)
Closed 5 years ago.
We try to parse the following ISO 8601 DateTime String with timezone offset:
final String input = "2022-03-17T23:00:00.000+0000";
OffsetDateTime.parse(input);
LocalDateTime.parse(input, DateTimeFormatter.ISO_OFFSET_DATE_TIME);
Both approaches fail (which makes sense as OffsetDateTime also use the DateTimeFormatter.ISO_OFFSET_DATE_TIME) because of the colon in the timezone offset.
java.time.format.DateTimeParseException: Text '2022-03-17T23:00:00.000+0000' could not be parsed at index 23
But according to Wikipedia there are 4 valid formats for a timezone offset:
<time>Z
<time>±hh:mm
<time>±hhmm
<time>±hh
Other frameworks/languages can parse this string without any issues, e.g. the Javascript Date() or Jacksons ISO8601Utils (they discuss this issue here)
Now we could write our own DateTimeFormatter with a complex RegEx, but in my opinion the java.time library should be able to parse this valid ISO 8601 string by default as it is a valid one.
For now we use Jacksons ISO8601DateFormat, but we would prefer to use the official date.time library to work with. What would be your approach to tackle this issue?
If you want to parse all valid formats of offsets (Z, ±hh:mm, ±hhmm and ±hh), one alternative is to use a java.time.format.DateTimeFormatterBuilder with optional patterns (unfortunatelly, it seems that there's no single pattern letter to match them all):
DateTimeFormatter formatter = new DateTimeFormatterBuilder()
// date/time
.append(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
// offset (hh:mm - "+00:00" when it's zero)
.optionalStart().appendOffset("+HH:MM", "+00:00").optionalEnd()
// offset (hhmm - "+0000" when it's zero)
.optionalStart().appendOffset("+HHMM", "+0000").optionalEnd()
// offset (hh - "Z" when it's zero)
.optionalStart().appendOffset("+HH", "Z").optionalEnd()
// create formatter
.toFormatter();
System.out.println(OffsetDateTime.parse("2022-03-17T23:00:00.000+0000", formatter));
System.out.println(OffsetDateTime.parse("2022-03-17T23:00:00.000+00", formatter));
System.out.println(OffsetDateTime.parse("2022-03-17T23:00:00.000+00:00", formatter));
System.out.println(OffsetDateTime.parse("2022-03-17T23:00:00.000Z", formatter));
All the four cases above will parse it to 2022-03-17T23:00Z.
You can also define a single string pattern if you want, using [] to delimiter the optional sections:
// formatter with all possible offset patterns
DateTimeFormatter formatter = DateTimeFormatter
.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS[xxx][xx][X]");
This formatter also works for all cases, just like the previous formatter above. Check the javadoc to get more details about each pattern.
Notes:
A formatter with optional sections like the above is good for parsing, but not for formatting. When formatting, it'll print all the optional sections, which means it'll print the offset many times. So, to format the date, just use another formatter.
The second formatter accepts exactly 3 digits after the decimal point (because of .SSS). On the other hand, ISO_LOCAL_DATE_TIME is more flexible: the seconds and nanoseconds are optional, and it also accepts from 0 to 9 digits after the decimal point. Choose the one that works best for your input data.
You don't need to write a complex regex - you can build a DateTimeFormatter that will work with that format easily:
DateTimeFormatter formatter =
DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss.SSSX", Locale.ROOT);
OffsetDateTime odt = OffsetDateTime.parse(input, formatter);
That will also accept "Z" instead of "0000". It will not accept "+00:00" (with the colon or similar. That's surprising given the documentation, but if your value always has the UTC offset without the colon, it should be okay.
I wouldn't call it a solution but a workaround. SimpleDateFormat's Z template supports the timezone-syntax you showed, so you can do something like this:
final String input = "2022-03-17T23:00:00.000+0000";
try {
OffsetDateTime.parse(input);
LocalDateTime.parse(input, DateTimeFormatter.ISO_OFFSET_DATE_TIME);
}
catch (DateTimeParseException e) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SZ", Locale.GERMANY);
sdf.parse(input);
}
You're still using official libraries shipped with the JVM. One isn't part of the date.time-library, but still ;-)
Since it is without colon, can you use your own format string :
final String input = "2022-03-17T23:00:00.000+0000";
DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
Date parsed = df.parse(input);
System.out.println(parsed);
This question already has answers here:
How to display time amount to user?
(1 answer)
Java 8 epoch-millis time stamp to formatted date, how?
(3 answers)
Closed 2 years ago.
I have a value in miliseconds 1601626934449
Which generated via https://docs.oracle.com/javase/7/docs/api/java/lang/System.html#currentTimeMillis()
but can I somehow be able to get time in human readable format, or in brief I need to be able to know what the value in miliseconds 1601626934449 is ?
Use java.time on Java 8 or higher. Using that, it's easy to reach your goal.
You basically create an Instant from the epoch milliseconds (which represent a moment in time), make it a ZonedDateTime by applying a ZoneId (my system's default in the following example) and then either format the output String by a built-in DateTimeFormatter or by creating a custom one with a desired pattern to make it as human-readable as required.
Here's an example:
public static void main(String[] args) {
// your example millis
long currentMillis = 1601626934449L;
// create an instant from those millis
Instant instant = Instant.ofEpochMilli(currentMillis);
// use that instant and a time zone in order to get a suitable datetime object
ZonedDateTime zdt = ZonedDateTime.ofInstant(instant, ZoneId.systemDefault());
// then print the (implicitly called) toString() method of it
System.out.println(currentMillis + " is " + zdt);
// or create a different human-readable formatting by means of a custom formatter
System.out.println(
zdt.format(
DateTimeFormatter.ofPattern(
"EEEE, dd. 'of' MMMM uuuu 'at' HH:mm:ss 'o''clock in' VV 'with an offset of' xxx 'hours'",
Locale.ENGLISH
)
)
);
}
which outputs (on my system)
1601626934449 is 2020-10-02T10:22:14.449+02:00[Europe/Berlin]
Friday, 02. of October 2020 at 10:22:14 o'clock in Europe/Berlin with an offset of +02:00 hours
You can convert millis into LocalDateTime to store time
long millis = System.currentTimeMillis();
LocalDateTime datetime = Instant.ofEpochMilli(millis)
.atZone(ZoneId.systemDefault()).toLocalDateTime();
Then you can print your data using toString() or your desire format using DateTimeFormatter.
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss.SSS");
System.out.println(datetime.format(formatter));
Output: 2020-10-02 18:39:54.609
You can create a Date object and use it to get all the information you need:
https://docs.oracle.com/javase/7/docs/api/java/util/Date.html#Date(long)
This question already has answers here:
Cannot parse String in ISO 8601 format, lacking colon in offset, to Java 8 Date
(3 answers)
Closed 5 years ago.
We try to parse the following ISO 8601 DateTime String with timezone offset:
final String input = "2022-03-17T23:00:00.000+0000";
OffsetDateTime.parse(input);
LocalDateTime.parse(input, DateTimeFormatter.ISO_OFFSET_DATE_TIME);
Both approaches fail (which makes sense as OffsetDateTime also use the DateTimeFormatter.ISO_OFFSET_DATE_TIME) because of the colon in the timezone offset.
java.time.format.DateTimeParseException: Text '2022-03-17T23:00:00.000+0000' could not be parsed at index 23
But according to Wikipedia there are 4 valid formats for a timezone offset:
<time>Z
<time>±hh:mm
<time>±hhmm
<time>±hh
Other frameworks/languages can parse this string without any issues, e.g. the Javascript Date() or Jacksons ISO8601Utils (they discuss this issue here)
Now we could write our own DateTimeFormatter with a complex RegEx, but in my opinion the java.time library should be able to parse this valid ISO 8601 string by default as it is a valid one.
For now we use Jacksons ISO8601DateFormat, but we would prefer to use the official date.time library to work with. What would be your approach to tackle this issue?
If you want to parse all valid formats of offsets (Z, ±hh:mm, ±hhmm and ±hh), one alternative is to use a java.time.format.DateTimeFormatterBuilder with optional patterns (unfortunatelly, it seems that there's no single pattern letter to match them all):
DateTimeFormatter formatter = new DateTimeFormatterBuilder()
// date/time
.append(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
// offset (hh:mm - "+00:00" when it's zero)
.optionalStart().appendOffset("+HH:MM", "+00:00").optionalEnd()
// offset (hhmm - "+0000" when it's zero)
.optionalStart().appendOffset("+HHMM", "+0000").optionalEnd()
// offset (hh - "Z" when it's zero)
.optionalStart().appendOffset("+HH", "Z").optionalEnd()
// create formatter
.toFormatter();
System.out.println(OffsetDateTime.parse("2022-03-17T23:00:00.000+0000", formatter));
System.out.println(OffsetDateTime.parse("2022-03-17T23:00:00.000+00", formatter));
System.out.println(OffsetDateTime.parse("2022-03-17T23:00:00.000+00:00", formatter));
System.out.println(OffsetDateTime.parse("2022-03-17T23:00:00.000Z", formatter));
All the four cases above will parse it to 2022-03-17T23:00Z.
You can also define a single string pattern if you want, using [] to delimiter the optional sections:
// formatter with all possible offset patterns
DateTimeFormatter formatter = DateTimeFormatter
.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS[xxx][xx][X]");
This formatter also works for all cases, just like the previous formatter above. Check the javadoc to get more details about each pattern.
Notes:
A formatter with optional sections like the above is good for parsing, but not for formatting. When formatting, it'll print all the optional sections, which means it'll print the offset many times. So, to format the date, just use another formatter.
The second formatter accepts exactly 3 digits after the decimal point (because of .SSS). On the other hand, ISO_LOCAL_DATE_TIME is more flexible: the seconds and nanoseconds are optional, and it also accepts from 0 to 9 digits after the decimal point. Choose the one that works best for your input data.
You don't need to write a complex regex - you can build a DateTimeFormatter that will work with that format easily:
DateTimeFormatter formatter =
DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss.SSSX", Locale.ROOT);
OffsetDateTime odt = OffsetDateTime.parse(input, formatter);
That will also accept "Z" instead of "0000". It will not accept "+00:00" (with the colon or similar. That's surprising given the documentation, but if your value always has the UTC offset without the colon, it should be okay.
I wouldn't call it a solution but a workaround. SimpleDateFormat's Z template supports the timezone-syntax you showed, so you can do something like this:
final String input = "2022-03-17T23:00:00.000+0000";
try {
OffsetDateTime.parse(input);
LocalDateTime.parse(input, DateTimeFormatter.ISO_OFFSET_DATE_TIME);
}
catch (DateTimeParseException e) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SZ", Locale.GERMANY);
sdf.parse(input);
}
You're still using official libraries shipped with the JVM. One isn't part of the date.time-library, but still ;-)
Since it is without colon, can you use your own format string :
final String input = "2022-03-17T23:00:00.000+0000";
DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
Date parsed = df.parse(input);
System.out.println(parsed);
I want to add a Z at the end of DateTimeFormatter ISO_DATE_TIME in Java not hard coded
String sample = "2018-05-11T13:35:11Z";
DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss[.SSS][XXX][X]");
DateTimeFormatter df1 = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss'Z'");
LocalDateTime newLocalDateTime = LocalDateTime.parse(sample, df1);
System.out.println(newLocalDateTime.toString());
Output is:
2018-05-11T13:35:11
I want the output to be 2018-05-11T13:35:11Z
You are calling toString() of your LocalDateTime, you should be calling format. Change
System.out.println(newLocalDateTime.toString());
to
System.out.println(newLocalDateTime.format(df1));
Outputs
2018-05-11T13:35:11Z
If you want the output to have a time zone offset like Z, you should use OffsetDateTime or ZonedDateTime.
LocalDateTime ldt = LocalDateTime.parse("2018-05-11T13:35:11");
OffsetDateTime odt = ldt.atOffset(ZoneOffset.UTC);
System.out.println(odt); // prints: 2018-05-11T13:35:11Z
ZonedDateTime zdt = ldt.atZone(ZoneOffset.UTC);
System.out.println(zdt); // prints: 2018-05-11T13:35:11Z
As you can see, the toString() method will return the date in the format you requested.
You shouldn’t use LocalDateTime. Use OffsetDateTime. And you may need no formatter.
String sample = "2018-05-11T13:35:11Z";
OffsetDateTime dateTime = OffsetDateTime.parse(sample)
.withOffsetSameInstant(ZoneOffset.UTC);
System.out.println(dateTime.toString());
Output from this snippet is the dsesired:
2018-05-11T13:35:11Z
The call to withOffsetSameInstant() makes sure that the date and time are in UTC even if the input had not been. I am using OffsetDateTime.toString() to produce the output string. I am exploiting the fact that both your sample string and your desired output are in ISO 8601 format. OffsetDateTime and the other classes from java.time parse ISO 8601 format as their default, that is, without any explicit formatter, and produce ISO 8601 format from their toString methods.
OffsetDateTime.toString() on one hand will leave out the seconds if they are 0, will on the other hand include a fraction of second if it is non-zero (all of this agress with ISO 8601). If you don’t want this, you do need a formatter. For example:
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ssX");
System.out.println(dateTime.format(formatter));
You are correct, you should not hardcode Z as a literal in the format pattern string. Z signifies an offset of zero from UTC. Use format pattern letter X to output the offset so you are sure the offset is always correct. This will print an offset of zero as Z.
A LocalDateTime doesn’t keep a UTC offset, so when parsing into one your are losing information. Don’t do this. Parse into an OffsetDateTime to pick up all the information from the string.
Link: Wikipedia article: ISO 8601
This question already has answers here:
Cannot parse String in ISO 8601 format, lacking colon in offset, to Java 8 Date
(3 answers)
Closed 5 years ago.
We try to parse the following ISO 8601 DateTime String with timezone offset:
final String input = "2022-03-17T23:00:00.000+0000";
OffsetDateTime.parse(input);
LocalDateTime.parse(input, DateTimeFormatter.ISO_OFFSET_DATE_TIME);
Both approaches fail (which makes sense as OffsetDateTime also use the DateTimeFormatter.ISO_OFFSET_DATE_TIME) because of the colon in the timezone offset.
java.time.format.DateTimeParseException: Text '2022-03-17T23:00:00.000+0000' could not be parsed at index 23
But according to Wikipedia there are 4 valid formats for a timezone offset:
<time>Z
<time>±hh:mm
<time>±hhmm
<time>±hh
Other frameworks/languages can parse this string without any issues, e.g. the Javascript Date() or Jacksons ISO8601Utils (they discuss this issue here)
Now we could write our own DateTimeFormatter with a complex RegEx, but in my opinion the java.time library should be able to parse this valid ISO 8601 string by default as it is a valid one.
For now we use Jacksons ISO8601DateFormat, but we would prefer to use the official date.time library to work with. What would be your approach to tackle this issue?
If you want to parse all valid formats of offsets (Z, ±hh:mm, ±hhmm and ±hh), one alternative is to use a java.time.format.DateTimeFormatterBuilder with optional patterns (unfortunatelly, it seems that there's no single pattern letter to match them all):
DateTimeFormatter formatter = new DateTimeFormatterBuilder()
// date/time
.append(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
// offset (hh:mm - "+00:00" when it's zero)
.optionalStart().appendOffset("+HH:MM", "+00:00").optionalEnd()
// offset (hhmm - "+0000" when it's zero)
.optionalStart().appendOffset("+HHMM", "+0000").optionalEnd()
// offset (hh - "Z" when it's zero)
.optionalStart().appendOffset("+HH", "Z").optionalEnd()
// create formatter
.toFormatter();
System.out.println(OffsetDateTime.parse("2022-03-17T23:00:00.000+0000", formatter));
System.out.println(OffsetDateTime.parse("2022-03-17T23:00:00.000+00", formatter));
System.out.println(OffsetDateTime.parse("2022-03-17T23:00:00.000+00:00", formatter));
System.out.println(OffsetDateTime.parse("2022-03-17T23:00:00.000Z", formatter));
All the four cases above will parse it to 2022-03-17T23:00Z.
You can also define a single string pattern if you want, using [] to delimiter the optional sections:
// formatter with all possible offset patterns
DateTimeFormatter formatter = DateTimeFormatter
.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS[xxx][xx][X]");
This formatter also works for all cases, just like the previous formatter above. Check the javadoc to get more details about each pattern.
Notes:
A formatter with optional sections like the above is good for parsing, but not for formatting. When formatting, it'll print all the optional sections, which means it'll print the offset many times. So, to format the date, just use another formatter.
The second formatter accepts exactly 3 digits after the decimal point (because of .SSS). On the other hand, ISO_LOCAL_DATE_TIME is more flexible: the seconds and nanoseconds are optional, and it also accepts from 0 to 9 digits after the decimal point. Choose the one that works best for your input data.
You don't need to write a complex regex - you can build a DateTimeFormatter that will work with that format easily:
DateTimeFormatter formatter =
DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss.SSSX", Locale.ROOT);
OffsetDateTime odt = OffsetDateTime.parse(input, formatter);
That will also accept "Z" instead of "0000". It will not accept "+00:00" (with the colon or similar. That's surprising given the documentation, but if your value always has the UTC offset without the colon, it should be okay.
I wouldn't call it a solution but a workaround. SimpleDateFormat's Z template supports the timezone-syntax you showed, so you can do something like this:
final String input = "2022-03-17T23:00:00.000+0000";
try {
OffsetDateTime.parse(input);
LocalDateTime.parse(input, DateTimeFormatter.ISO_OFFSET_DATE_TIME);
}
catch (DateTimeParseException e) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SZ", Locale.GERMANY);
sdf.parse(input);
}
You're still using official libraries shipped with the JVM. One isn't part of the date.time-library, but still ;-)
Since it is without colon, can you use your own format string :
final String input = "2022-03-17T23:00:00.000+0000";
DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
Date parsed = df.parse(input);
System.out.println(parsed);