Any Difference Between Java.Time.Clock.Systemdefaultzone().Getzone() VS Java.Util.Timezone.Getdefault().Tozoneid()

Any difference between java.time.Clock.systemDefaultZone().getZone() vs java.util.TimeZone.getDefault().toZoneId()?

Both returns the JVM's default timezone (in the end, Clock calls TimeZone.getDefault(), as explained in @Kiskae's answer), but it's not guaranteed that all calls will always return the same value everytime.

That's because the default timezone can be changed:

  • the system where the JVM is running can change its configuration. In Windows machines, for example, this information is read from the registry, while in Linux it gets from /etc/localtime (usually a link to a specific file in /usr/share/zoneinfo) or another similar folder (it can vary in each version/distribution), or by setting the TZ environment variable. If this system configuration changes it and the JVM is restarted, suddenly your code starts returning different values
  • the JVM can be configured to use a different timezone, regardless of OS's config. One example is when the maintanance/infrastructure team changes this configuration (on purpose or by accident, and usually without telling the developers...) and then your code doesn't return the same values anymore (and everything that depends on the timezone will suddenly break)
  • your application (or another application running the same JVM) calls TimeZone.setDefault() method. This will affect all the applications running in the same JVM, at runtime, so if you run this code:

    TimeZone.setDefault(TimeZone.getTimeZone("Europe/London"));
    System.out.println(ZoneId.systemDefault());

    TimeZone.setDefault(TimeZone.getTimeZone("America/New_York"));
    System.out.println(ZoneId.systemDefault());

    TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
    System.out.println(ZoneId.systemDefault());

The output will be:

Europe/London

America/New_York

UTC

Note how easily the default timezone is changed at runtime, and all subsequent calls to get it are affected. The same will happen if you call Clock.systemDefaultZone().getZone() or TimeZone.getDefault().toZoneId(), because both uses the default timezone.

As this changes the JVM's default timezone, all applications running in the same JVM will be affected by it. This might lead to unexpected errors that are hard to debug.

Although the methods that use the default timezone are convenient, you must check how your code depends on it and how it can be affected if the zone changes.

If you don't want to depend on the default, the ideal is to use a specific timezone, such as ZoneId.of("Europe/Paris"). Always prefer IANA timezones names (always in the format Region/City, like America/New_York or Europe/Paris).
Avoid using the short abbreviations (like CET or CEST) 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().

Getting 4 hours difference while getting while converting data in to device timezone?

SimpleDateFormat and Calendar uses the JVM default timezone (unless you set a different one on them), and the default timezone can be different in each device/machine/environment. Not only that, this default can be changed without notice, even at runtime, so it's better to always make it explicit which one you're using.

When you do things like:

Calendar c = Calendar.getInstance(Locale.getDefault());
dateFormatter.setTimeZone(c.getTimeZone());
monthFormat.setTimeZone(TimeZone.getTimeZone(TimeZone.getDefault().getDisplayName()));

The Calendar is created with the default timezone, so dateFormatter will also have the same zone. So does monthFormat, and also the other formatters you created. The only formatter set to a different zone is the first one (which is set to UTC).

Also, the second formatter is redundant (it does the same thing that the first one is already doing: parsing the String to a Date), so you can remove it.

Assuming that your input is a String with the value 2018-09-30T13:45:00Z: the Z in the end indicates that this date is in UTC. So you should parse it using a formatter set to UTC. So, instead of using c.getTimeZone() and TimeZone.getDefault(), you should use only TimeZone.getTimeZone("UTC").

For the output, you must set the formatters with the timezone you want to convert to. If the timezone is "EDT", set to it (but don't use exactly "EDT", see below). If you want to use the JVM default, use TimeZone.getDefault() - just check this value before, to make sure the default is what you need.

Just keep in mind that short names like "EDT" and "EST" are not real timezones. Those abbreviations are ambiguous and not standard. Prefer to use IANA timezones names (always in the format Region/City, like America/New_York or Europe/Berlin).

So, when you do TimeZone.getTimeZone("EDT"), it usually returns "GMT" (because "EDT" is not recognized, and "GMT" is returned as default). That's because "EDT" is used by more than one timezone, so you must choose specifically which one you're using (I'm using America/New_York in these examples).

Another detail is that in the first 2 formatters you use hh, which means "hour of am/pm" (values from 1 to 12), but the input doesn't have AM/PM designators to properly resolve this. You need to change it to HH ("hour of day", with values from 0 to 23).

    // input is in UTC
TimeZone inputZone = TimeZone.getTimeZone("UTC");
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
formatter.setTimeZone(inputZone);
Date localStartDate = formatter.parse(startTime);
Date localEndDate = formatter.parse(endTime);
...

// removed the second formatter (it was redundant)

// output is in EST (America/New_York)
// or use TimeZone.getDefault() to get JVM default timezone
TimeZone outputZone = TimeZone.getTimeZone("America/New_York");
SimpleDateFormat monthFormat = new SimpleDateFormat("MMM");
monthFormat.setTimeZone(outputZone);
...

SimpleDateFormat dateFormat = new SimpleDateFormat("dd");
dateFormat.setTimeZone(outputZone);
...

SimpleDateFormat dayNameFormat = new SimpleDateFormat("EEEE");
dayNameFormat.setTimeZone(outputZone);
...

SimpleDateFormat timeFormat = new SimpleDateFormat("hh:mm a");
timeFormat.setTimeZone(outputZone);
...

System.out.println("My Start date and end date==>>>" + startTimeName + " " + endTimeName);

With this, you're explicity using UTC for input and a specific timezone for output, instead of relying on the JVM default timezone (which can be different in each device and you can't control).

The output is:

My Start date and end date==>>>08:15 AM 09:45 AM


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.

In Android you can use the ThreeTen Backport, a great backport for Java 8's new date/time classes. To make it work, you'll also need the ThreeTenABP (more on how to use it here).

First you can use a org.threeten.bp.Instant to parse the input, because it's in UTC (designated by the Z in the end). Then you use a org.threeten.bp.ZoneId to convert it to a org.threeten.bp.ZonedDateTime:

// output timezone
// or use ZoneId.systemDefault() to get JVM default timezone
ZoneId zone = ZoneId.of("America/New_York");
// parse the inputs
ZonedDateTime startDate = Instant.parse(startTime).atZone(zone);
ZonedDateTime endDate = Instant.parse(endTime).atZone(zone);

Then you can use these objects to get the other fields:

// get month name
System.out.println(startDate.getMonth().getDisplayName(TextStyle.SHORT, Locale.getDefault()));

This is equivalent to MMM pattern, and it will print the month name in the default locale. If you want the month name in a specific language, just use another java.util.Locale value (such as Locale.ENGLISH or any other one as described in the javadoc).

The org.threeten.bp.format.TextStyle defines if the month name will be narrow (usually just one letter), short (usually 2 or 3 letters) or full (the full name). The output varies according to the locale used.

I personally prefer to not use the default locale, because it can be changed without notice, even at runtime. It's always better to specify the locale you want.

To get the day of month, you can choose to get it as an int or as a formatted String (using a org.threeten.bp.format.DateTimeFormatter):

// get day of month as int
int day = startDate.getDayOfMonth(); // 30
// get day of month as formatted string
String dayStr = DateTimeFormatter.ofPattern("dd").format(startDate); // 30

To get the day of week, it's similar to the code used to get the month:

// get day of week
System.out.println(startDate.getDayOfWeek().getDisplayName(TextStyle.FULL, Locale.getDefault()));

The same logic applies here: the TextStyle defines how the name will be (in this case, FULL is equivalen to EEEE, and it prints the full name), and the locale defines the language used.

Finally, to get the corresponding time, you can use another DateTimeFormatter:

// get time
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("hh:mm a");
System.out.println(fmt.format(startDate)); // 08:15 AM
System.out.println(fmt.format(endDate)); // 09:45 AM

This will the date/time in the timezone you chose for the output.

If you're going to use the JVM default (ZoneId.systemDefault()), just check its value before to make sure it's the one you want (it might not be because this can be changed at runtime, so it's always better to specify one).

Java 8 Time API - ZonedDateTime - specify default ZoneId when parsing

A ZonedDateTime needs a timezone or an offset to be built, and the second input doesn't have it. (It contains only a date and time).

So you need to check if it's possible to build a ZonedDateTime, and if it's not, you'll have to choose an arbitrary zone for it (as the input has no indication about what's the timezone being used, you must choose one to be used).

One alternative is to first try to create a ZonedDateTime and if it's not possible, then create a LocalDateTime and convert it to a timezone:

public ZonedDateTime parseToZonedDateTime(String date, String dateFormat) {
// use java.time from java 8
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(dateFormat);
ZonedDateTime zonedDateTime = null;
try {
zonedDateTime = ZonedDateTime.parse(date, formatter);
} catch (DateTimeException e) {
// couldn't parse to a ZoneDateTime, try LocalDateTime
LocalDateTime dt = LocalDateTime.parse(date, formatter);

// convert to a timezone
zonedDateTime = dt.atZone(ZoneId.systemDefault());
}
return zonedDateTime;
}

In the code above, I'm using ZoneId.systemDefault(), which gets the JVM default timezone, but this can be changed without notice, even at runtime, so it's better to always make it explicit which one you're using.

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().

If you want to use a specific timezone, just use ZoneId.of("America/New_York") (or any other valid name returned by ZoneId.getAvailableZoneIds(), New York is just an example) instead of ZoneId.systemDefault().


Another alternative is to use parseBest() method, that tries to create a suitable date object (using a list of TemporalQuery's) until it creates the type you want:

public ZonedDateTime parseToZonedDateTime(String date, String dateFormat) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(dateFormat);

// try to create a ZonedDateTime, if it fails, try LocalDateTime
TemporalAccessor parsed = formatter.parseBest(date, ZonedDateTime::from, LocalDateTime::from);

// if it's a ZonedDateTime, return it
if (parsed instanceof ZonedDateTime) {
return (ZonedDateTime) parsed;
}
if (parsed instanceof LocalDateTime) {
// convert LocalDateTime to JVM default timezone
LocalDateTime dt = (LocalDateTime) parsed;
return dt.atZone(ZoneId.systemDefault());
}

// if it can't be parsed, return null or throw exception?
return null;
}

In this case, I just used ZonedDateTime::from and LocalDateTime::from, so the formatter will try to first create a ZonedDateTime, and if it's not possible, then it tries to create a LocalDateTime.

Then I check what was the type returned and do the actions accordingly.
You can add as many types you want (all main types, such as LocalDate, LocalTime, OffsetDateTime and so on, have a from method that works with parseBest - you can also create your own custom TemporalQuery if you want, but I think the built-in methods are enough for this case).



Daylight Saving Time

When converting a LocalDateTime to a ZonedDateTime using the atZone() method, there are some tricky cases regarding Daylight Saving Time (DST).

I'm going to use the timezone I live in (America/Sao_Paulo) as example, but this can happen at any timezone with DST.

In São Paulo, DST started at October 16th 2016: at midnight, clocks shifted 1 hour forward from midnight to 1 AM (and the offset changes from -03:00 to -02:00). So all local times between 00:00 and 00:59 didn't exist in this timezone (you can also think that clocks changed from 23:59:59.999999999 directly to 01:00). If I create a local date in this interval, it's adjusted to the next valid moment:

ZoneId zone = ZoneId.of("America/Sao_Paulo");

// October 16th 2016 at midnight, DST started in Sao Paulo
LocalDateTime d = LocalDateTime.of(2016, 10, 16, 0, 0, 0, 0);
ZonedDateTime z = d.atZone(zone);
System.out.println(z);// adjusted to 2017-10-15T01:00-02:00[America/Sao_Paulo]

When DST ends: in February 19th 2017 at midnight, clocks shifted back 1 hour, from midnight to 23 PM of 18th (and the offset changes from -02:00 to -03:00). So all local times from 23:00 to 23:59 existed twice (in both offsets: -03:00 and -02:00), and you must decide which one you want.
By default, it uses the offset before DST ends, but you can use the withLaterOffsetAtOverlap() method to get the offset after DST ends:

// February 19th 2017 at midnight, DST ends in Sao Paulo
// local times from 23:00 to 23:59 at 18th exist twice
LocalDateTime d = LocalDateTime.of(2017, 2, 18, 23, 0, 0, 0);
// by default, it gets the offset before DST ends
ZonedDateTime beforeDST = d.atZone(zone);
System.out.println(beforeDST); // before DST end: 2018-02-17T23:00-02:00[America/Sao_Paulo]

// get the offset after DST ends
ZonedDateTime afterDST = beforeDST.withLaterOffsetAtOverlap();
System.out.println(afterDST); // after DST end: 2018-02-17T23:00-03:00[America/Sao_Paulo]

Note that the dates before and after DST ends have different offsets (-02:00 and -03:00). If you're working with a timezone that has DST, keep in mind that those corner-cases can happen.

Hours difference while considering the date

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());

Receiving same ZonedDateTime for different time strings

When you call LocalDate.parse, you're getting just the date part (day, month and year) and discarding the rest. A LocalDate doesn't have the time fields (hour, minute, seconds and fraction of second), so they are simply discarded and lost.

Then you call atStartOfDay(ZoneId.systemDefault()), which sets the time to midnight at the JVM default timezone.

If you want to keep everything (date and time), parse it to a LocalDateTime, which is a class that contains all the date and time fields. Then you call the atZone method to convert it to a ZonedDateTime:

String inputTime = "20171025-10:58:24.062151";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd-HH:mm:ss.SSSSSS");
// parse to a LocalDateTime (keeping all date and time fields)
LocalDateTime date = LocalDateTime.parse(inputTime, formatter);
// convert to ZonedDateTime
ZonedDateTime z = date.atZone(ZoneId.systemDefault());

PS: ZoneId.systemDefault() returns the JVM default timezone, but keep in mind that this can be changed without notice, even at runtime, so it's better to always make it explicit which one you're using.

The API uses IANA timezones names (always in the format Region/City, like Asia/Colombo or Europe/Berlin).
Avoid using the 3-letter abbreviations (like IST or CET) 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(). Then you call the ZoneId.of() method with the zone name, like this:

// using specific timezone instead of JVM's default
ZonedDateTime z = date.atZone(ZoneId.of("Asia/Colombo"));

Mocking time in Java 8's java.time API

The closest thing is the Clock object. You can create a Clock object using any time you want (or from the System current time). All date.time objects have overloaded now methods that take a clock object instead for the current time. So you can use dependency injection to inject a Clock with a specific time:

public class MyBean {
private Clock clock; // dependency inject
...
public void process(LocalDate eventDate) {
if (eventDate.isBefore(LocalDate.now(clock)) {
...
}
}
}

See Clock JavaDoc for more details

How to set a JVM TimeZone Properly

You can pass the JVM this param

-Duser.timezone

For example

-Duser.timezone=Europe/Sofia

and this should do the trick.
Setting the environment variable TZ also does the trick on Linux.

Android and iOS libraries behave as if there never was a daylight saving time before 1996

In Java, SimpleDateFormat uses the JVM default timezone if you don't set one in it. (check what's yours with TimeZone.getDefault()).

So 1993-10-06T00:00+02:00 is converted to 1993-10-05T23:00+01:00 probably because the default timezone is one with +01:00 offset in October 1993, while in October 1996 it was in DST (+02:00). My guess is Europe/Paris, but it can be other, as lots of timezones uses CET as a short name.

Anyway, just check the history of DST in Paris and note that in October 1993 the offset was +01:00 while in October 6th 1996 it was +02:00. So it's a good guess, but any timezone with the same rules will have the same behaviour.

Also, +02:00 is an offset, not a timezone. Just being +02:00 doesn't necessarily mean that it's CET during DST, because there's more than one timezone that uses this offset. And short names like CET are ambiguous and not standard, so you should consider using IANA timezones names (always in the format Region/City, like America/Sao_Paulo or Europe/Paris).

Anyway, if you don't want to have variable offsets, you shouldn't rely on the JVM default timezone, because it can have DST effects and the offset will vary according to the date (and the default timezone can be changed without notice, even at runtime). One way to avoid it, is to set a fixed offset in the formatter:

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSSSSSZZZZZ");
// set the offset +02:00, so all dates will be formatted using this
// (instead of the current offset for the JVM default timezone)
sdf.setTimeZone(TimeZone.getTimeZone("GMT+02:00"));
Date date = sdf.parse("1993-10-06T00:00:00.0000000+02:00");
System.out.println(sdf.format(date));

Just some quick notes:

  • SimpleDateFormat doesn't work well with more than 3 digits after the decimal point. In the case above, it works fine because it's all zeroes, but if you have any value different from zero and more than 3 digits, you can have strange, wrong, unexpected results. In this case, you should remove the extra digits, because this class simply can't handle more than 3 (and it also doesn't work well for formatting).
  • I'm testing with JDK 7, so the pattern ZZZZZ doesn't work for parsing. Instead, I've used yyyy-MM-dd'T'HH:mm:ss.SSSSSSSXXX, which parses the inputs above, and formats the date to 1993-10-06T00:00:00.0000000+02:00 (but note that the X is not available in JDK 6)
  • If you want the output in another offset, just change it accordingly in the getTimeZone method. If you want UTC, use getTimeZone("UTC")

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.

In Android, you can use the ThreeTen Backport, a great backport for Java 8's new date/time classes. To make it work, you'll also need the ThreeTenABP (more on how to use it here).

One improvement in this new API is the support to nanoseconds (up to 9 digits after the decimal point), so it can handle your inputs without the problems of SimpleDateFormat.

This new API also has lots of new date/time types suited for different situations. In this case, you have a date and time in a specific offset, and wish to maintain it. So, the best class is a org.threeten.bp.OffsetDateTime:

OffsetDateTime odt = OffsetDateTime.parse("1993-10-06T00:00:00.0000000+02:00");
System.out.println(odt.toString()); // 1993-10-06T00:00+02:00

Note that the toString() method omits the seconds and nanoseconds if they are zero. If you want the output exactly like the input (with 7 digits after the decimal point), just create a org.threeten.bp.format.DateTimeFormatter:

DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSSSSSXXX");
System.out.println(fmt.format(odt)); // 1993-10-06T00:00:00.0000000+02:00

To change this to another offset (or to UTC), use a org.threeten.bp.ZoneOffset:

// convert to UTC
odt = odt.withOffsetSameInstant(ZoneOffset.UTC);
System.out.println(fmt.format(odt)); // 1993-10-05T22:00:00.0000000Z

// convert to another offset (+01:00)
odt = odt.withOffsetSameInstant(ZoneOffset.ofHours(1));
System.out.println(fmt.format(odt)); // 1993-10-05T23:00:00.0000000+01:00


Related Topics



Leave a reply



Submit