I'm trying to parse 2009-07-30T16:10:36+06:00 to a date using yyyy-MM-dd'T'HH:mm:ssXXXXX.
However the output I get appears to have not factored in the offset, as I get yyyy-MM-dd'T'HH:mm:ssXXXXX.
Any ideas what I'm missing?
final DateTimeFormatter iso8601Formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssXXXXX");
final ZonedDateTime zonedDateTime = ZonedDateTime.parse("2009-07-30T16:10:36+06:00", iso8601Formatter);
final String formatted = zonedDateTime.format(DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ss"));
System.out.println(formatted);
If my understanding is correct you should set the zone similar to withZoneSameInstant(ZoneId.of("UTC"))
final ZonedDateTime zonedDateTime = ZonedDateTime.parse("2009-07-30T16:10:36+06:00", DateTimeFormatter.ISO_OFFSET_DATE_TIME);
System.out.println("Without ZoneId: " + zonedDateTime.format(DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ss")));
System.out.println("With ZoneId: " + zonedDateTime.withZoneSameInstant(ZoneOffset.UTC).format(DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ss")));
Result
Without ZoneId: 30/07/2009 16:10:36
With ZoneId: 30/07/2009 10:10:36
OffsetDateTime odt = OffsetDateTime.parse("2009-07-30T16:10:36+06:00");
ZonedDateTime zdt = ZonedDateTime.ofInstant(odt.toInstant(), ZoneOffset.UTC);
// 2009-07-30T10:10:36Z
First you have no zoned date time, which would also depend on the country.
Then actually you want the Greenwich time, the UTC.
If you want the time in UTC (which is not clear from the question), then the other answers give you the correct result. Since there is no time zone (such as Europe/London Pacific/Rarotonga) in your data, there is no point in using a ZonedDateTime. OffsetDateTime is a better fit:
final OffsetDateTime dateTime = OffsetDateTime.parse("2009-07-30T16:10:36+06:00");
final OffsetDateTime utcDateTime = dateTime.withOffsetSameInstant(ZoneOffset.UTC);
final String formatted = utcDateTime.format(DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ss"));
System.out.println(formatted);
30/07/2009 10:10:36
Related
I have tried multiple ways one of them using SimpleDateFromatter and now trying
import java.sql.Timestamp;
public static String getCorrectTimeFormat(Timestamp time) {
return time.toInstant().toString();
}
But the problem is which I realized during writing unit test is, the time gets modified.
Timestamp timeStamp = Timestamp.valueOf("2020-07-22 12:26:51.599");
String res = UserUtil.getCorrectTimeFormat(timeStamp);
assertThat(res).isEqualTo("2020-07-22T12:26:51.599Z");
This never passes as the it auto converts to "2020-07-22T11:26:51.599Z"
It’s best to avoid jqva.sql.Timestamp completely. I’ll show you how.
The result you got is correct, as I think you have already discovered.
Get java.time types from your database
Since JDBC 4.2 we can directly get java.time types from a ResultSet. If your database value is a timestamp with time zone (recommended), for example:
OffsetDateTime odt = rs.getObject(
"your_timestamp_with_time_zone_column", OffsetDateTime.class);
String utcString = odt.withOffsetSameInstant(ZoneOffset.UTC).toString();
If your database value is a timestamp without time zone (not recommended), we can only get a LocalDateTime from it, which doesn’t define a point in time. To convert to Instant we need to rely on knowing which time zone the database uses. For example:
ZoneId datebaseTimeZone = ZoneId.of("Europe/Paris");
LocalDateTime ldt = rs.getObject(
"your_timestamp_column", LocalDateTime.class);
String utcString = ldt.atZone(datebaseTimeZone)
.withZoneSameInstant(ZoneOffset.UTC)
.toString();
If your database uses UTC, which counts as an offset, it’s better to use ZoneOffset than ZoneId:
ZoneOffset datebaseOffset = ZoneOffset.UTC;
LocalDateTime ldt = rs.getObject(
"your_timestamp_column", LocalDateTime.class);
String utcString = ldt.atOffset(datebaseOffset).toString();
Your observed result is correct
java.sql.Timestamp confusingly prints in the default time zone of the JVM, and Timestamp.valueOf() equally confusingly assumes that time zone. So assuming that your time zone is at offset +01:00 at this time of year (such as Great Britain, Ireland, Portugal, Morocco and Tunesia, for example), the conversion from 2020-07-22 12:26:51.599 to 2020-07-22T11:26:51.599Z is correct.
You can use java 8 time ZonedDateTime class :
//1 - default pattern
String timeStamp = "2019-03-27T10:15:30";
ZonedDateTime localTimeObj = ZonedDateTime.parse(time);
//2 - specified pattern
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss a z");
String timeStamp1 = "2019-03-27 10:15:30 AM";
ZonedDateTime localTimeObj1 = ZonedDateTime.parse(timeStamp1, formatter);
//To get LocalDate from ZonedDateTime
LocalDate localDate = localTimeObj1.toLocalDate()
//To get timestamp from zoneddatetime with utc timezone
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
ZonedDateTime zonedDateTime = ZonedDateTime.now(ZoneOffset.UTC);
Timestamp timestamp = Timestamp.from(ZonedDateTime.now(ZoneOffset.UTC).toInstant());
I'm trying to format an Instant to a String using the new Java 8 Date and Time API and the following pattern:
Instant instant = ...;
String out = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(instant);
Using the code above I get an exception which complains about an unsupported field:
java.time.temporal.UnsupportedTemporalTypeException: Unsupported field: YearOfEra
at java.time.Instant.getLong(Instant.java:608)
at java.time.format.DateTimePrintContext.getValue(DateTimePrintContext.java:298)
...
Time Zone
To format an Instant a time-zone is required. Without a time-zone, the formatter does not know how to convert the instant to human date-time fields, and therefore throws an exception.
The time-zone can be added directly to the formatter using withZone().
DateTimeFormatter formatter =
DateTimeFormatter.ofLocalizedDateTime( FormatStyle.SHORT )
.withLocale( Locale.UK )
.withZone( ZoneId.systemDefault() );
If you specifically want an ISO-8601 format with no explicit time-zone
(as the OP asked), with the time-zone implicitly UTC, you need
DateTimeFormatter.ISO_LOCAL_DATE_TIME.withZone(ZoneId.from(ZoneOffset.UTC))
Generating String
Now use that formatter to generate the String representation of your Instant.
Instant instant = Instant.now();
String output = formatter.format( instant );
Dump to console.
System.out.println("formatter: " + formatter + " with zone: " + formatter.getZone() + " and Locale: " + formatter.getLocale() );
System.out.println("instant: " + instant );
System.out.println("output: " + output );
When run.
formatter: Localized(SHORT,SHORT) with zone: US/Pacific and Locale: en_GB
instant: 2015-06-02T21:34:33.616Z
output: 02/06/15 14:34
public static void main(String[] args) {
DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
.withZone(ZoneId.systemDefault());
System.out.println(DATE_TIME_FORMATTER.format(new Date().toInstant()));
}
DateTimeFormatter.ISO_INSTANT.format(Instant.now())
This saves you from having to convert to UTC. However, some other language's time frameworks may not support the milliseconds so you should do
DateTimeFormatter.ISO_INSTANT.format(Instant.now().truncatedTo(ChronoUnit.SECONDS))
The Instant class doesn't contain Zone information, it only stores timestamp in milliseconds from UNIX epoch, i.e. 1 Jan 1070 from UTC.
So, formatter can't print a date because date always printed for concrete time zone.
You should set time zone to formatter and all will be fine, like this :
Instant instant = Instant.ofEpochMilli(92554380000L);
DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT).withLocale(Locale.UK).withZone(ZoneOffset.UTC);
assert formatter.format(instant).equals("07/12/72 05:33");
assert instant.toString().equals("1972-12-07T05:33:00Z");
Instants are already in UTC and already have a default date format of yyyy-MM-dd. If you're happy with that and don't want to mess with time zones or formatting, you could also toString() it:
Instant instant = Instant.now();
instant.toString()
output: 2020-02-06T18:01:55.648475Z
Don't want the T and Z? (Z indicates this date is UTC. Z stands for "Zulu" aka "Zero hour offset" aka UTC):
instant.toString().replaceAll("[TZ]", " ")
output: 2020-02-06 18:01:55.663763
Want milliseconds instead of nanoseconds? (So you can plop it into a sql query):
instant.truncatedTo(ChronoUnit.MILLIS).toString().replaceAll("[TZ]", " ")
output: 2020-02-06 18:01:55.664
etc.
Or if you still want to use formatter created from pattern
you can just use LocalDateTime instead of Instant:
LocalDateTime datetime = LocalDateTime.now();
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(datetime)
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy MM dd");
String text = date.toString(formatter);
LocalDate date = LocalDate.parse(text, formatter);
I believe this might help, you may need to use some sort of localdate variation instead of instant
final Timestamp rawDateTime = Timestamp.valueOf("2031-04-25 18:30:00");
final ZoneId zoneId = ZoneId.of("Asia/Calcutta");
final ZonedDateTime zonedDateTime = ZonedDateTime.ofInstant(
Instant.ofEpochMilli(rawDateTime.getTime()), zoneId);
// here we are getting output as 2031-04-25T18:30+05:30[Asia/Calcutta]
final ZonedDateTime zonedDateTime1 =
ZonedDateTime.of(rawDateTime.toLocalDateTime(), zoneId);
// here we are getting output as 2031-04-25T18:30+05:30[Asia/Calcutta]
But I want to get the converted date time as 2031-04-26 00:00:00+5:30 as my timestamp value is in the UTC Timezone.
Please help.
First, you should not use Timestamp. You can use DateTimeFormatter to parse into a LocalDateTime.
You then zone that LocalDateTime to UTC before converting to the Calcutta zone with ZonedDateTime.withZoneSameInstant.
DateTimeFormatter formatter = new DateTimeFormatterBuilder()
.append(DateTimeFormatter.ISO_LOCAL_DATE)
.appendLiteral(' ')
.append(DateTimeFormatter.ISO_LOCAL_TIME)
.toFormatter();
LocalDateTime localDateTime = LocalDateTime.parse("2031-04-25 18:30:00", formatter);
ZoneId calcuttaZone = ZoneId.of("Asia/Calcutta");
ZonedDateTime calcuttaZonedDateTime = localDateTime.atZone(ZoneOffset.UTC)
.withZoneSameInstant(calcuttaZone);
Using DateTimeFormatter to format ZonedDateTime:
final Timestamp rawDateTime = Timestamp.valueOf("2031-04-25 18:30:00");
final ZoneId zoneId = ZoneId.of("Asia/Calcutta");
final ZonedDateTime zonedDateTime = ZonedDateTime.ofInstant(
Instant.ofEpochMilli(rawDateTime.getTime()), zoneId);
// here we are getting output as 2031-04-25T18:30+05:30[Asia/Calcutta]
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss[XXX]");
System.out.println(formatter.format(zonedDateTime));
final ZonedDateTime zonedDateTime1 =
ZonedDateTime.of(rawDateTime.toLocalDateTime(), zoneId);
// here we are getting output as 2031-04-25T18:30+05:30[Asia/Calcutta]
System.out.println(formatter.format(zonedDateTime1));
The output:
2031-04-25 23:00:00+05:30
2031-04-25 18:30:00+05:30
Edited: according to the comment from #Ole V.V. - The local date time has to be converted to the zonedatetime , before applying the format :
final Timestamp rawDateTime = Timestamp.valueOf("2031-04-25 18:30:00");
LocalDateTime ldt = rawDateTime.toLocalDateTime();
final ZoneId zoneId = ZoneId.of("Asia/Calcutta");
ZonedDateTime zdt = ldt.atZone(ZoneId.of("UTC"))
.withZoneSameInstant(zoneId);
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss[XXX]");
System.out.println(formatter.format(zdt));
This will give the output:
2031-04-26 00:00:00+5:30
Instead of ZonedDateTime with named zones having (supra-)national standards like day-time-savings, use OffsetDateTime.
OffsetDateTime utc = OffsetDateTime.parse("2031-04-25T18:30:00Z");
OffsetDateTime asia = utc.withOffsetSameInstant(ZoneOffset.ofHoursMinutes(5, 30));
The default parsing is for the ISO format.
Z means zero, UTC, +0:00.
The resulting default formatting is 2031-04-26T00:00+05:30.
After comment of Ole V.V.
The above is especially error prone if summer time is involved, like in Central European Time with varying offsets +1:00 and +2:00.
Instant raw = Instant.parse("2031-04-25T18:30:00Z");
ZonedDateTime zoned = raw.atZone(ZoneId.of("Asia/Calcutta"));
OffsetDateTime offset = OffsetDateTime.from(zoned);
I have a datetime-string WITHOUT a specified timezone.
But I want to parse it with ZonedDateTime to give it a timezone-meaning in the act of parsing.
This code is working but uses LocalDateTime for parsing - and then convert it to ZonedDateTime with giving it a timezone-meaning.
DateTimeFormatter dtf = DateTimeFormatter.ofPattern ("yyyyMMddHHmm");
String tmstr = "201810110907";
LocalDateTime tmp = LocalDateTime.parse (tnstr,dtf);
ZonedDateTime mytime = ZonedDateTime.of (tmp, ZoneId.of ("UTC"));
Is there a way I can parse it directly with ZonedDateTime?
I have tried this, but it was not working.
mytime = mytime.withZoneSameInstant(ZoneId.of("UTC")).parse(str,dtf);
You may specify a default time zone on the formatter:
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyyMMddHHmm")
.withZone(ZoneId.of("UTC"));
String tmstr = "201810110907";
ZonedDateTime mytime = ZonedDateTime.parse(tmstr, dtf);
System.out.println(mytime);
Output:
2018-10-11T09:07Z[UTC]
Bonus tip: Rather than ZoneId.of("UTC") it’s usually nicer to use ZoneOffset.UTC. If you accept the output being printed as 2018-10-11T09:07Z instead (Z meaning UTC).
I have a time with string type like: "2015-01-05 17:00" and ZoneId is "Australia/Sydney".
How can I convert this time information to the corresponding to UTC time using Java 8 datetime API?
Also need to considering DST stuff.
You are looking for ZonedDateTime class in Java8 - a complete date-time with time-zone and resolved offset from UTC/Greenwich. In terms of design, this class should be viewed primarily as the combination of a LocalDateTime and a ZoneId. The ZoneOffset is a vital, but secondary, piece of information, used to ensure that the class represents an instant, especially during a daylight savings overlap.
For example:
ZoneId australia = ZoneId.of("Australia/Sydney");
String str = "2015-01-05 17:00";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
LocalDateTime localtDateAndTime = LocalDateTime.parse(str, formatter);
ZonedDateTime dateAndTimeInSydney = ZonedDateTime.of(localtDateAndTime, australia );
System.out.println("Current date and time in a particular timezone : " + dateAndTimeInSydney);
ZonedDateTime utcDate = dateAndTimeInSydney.withZoneSameInstant(ZoneOffset.UTC);
System.out.println("Current date and time in UTC : " + utcDate);
An alternative to the existing answer is to setup the formatter with the appropriate time zone:
String input = "2015-01-05 17:00";
ZoneId zone = ZoneId.of("Australia/Sydney");
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm").withZone(zone);
ZonedDateTime utc = ZonedDateTime.parse(input, fmt).withZoneSameInstant(UTC);
Since you want to interact with a database, you may need a java.sql.Timestamp, in which case you don't need to explicitly convert to a UTC time but can use an Instant instead:
ZonedDateTime zdt = ZonedDateTime.parse(input, fmt);
Timestamp sqlTs = Timestamp.from(zdt.toInstant());
**// Refactored Logic**
ZoneId australia = ZoneId.of("Australia/Sydney");
ZoneId utcZoneID= ZoneId.of("Etc/UTC");
String ausTime = "2015-01-05 17:00";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
//converting in datetime of java8
LocalDateTime ausDateAndTime = LocalDateTime.parse(ausTime, formatter);
// DateTime With Zone
ZonedDateTime utcDateAndTime = ausDateAndTime.atZone(utcZoneID);
// output - 2015-01-05T17:00Z[Etc/UTC]
// With Formating DateTime
String utcDateTime = utcDateAndTime.format(formatter);
// output - 2015-01-05 17:00