3

I have to display local date time for different countries in java.Currently I am setting zoneId for "America/New_York" and so only getting EST time for all the places on the server.How to achieve local date/time dynamically.

DateTimeFormatter globalFormat = DateTimeFormatter.ofPattern("dd-MMM-yyyy hh:mm a z");
DateTimeFormatter estFormat = DateTimeFormatter.ofPattern("dd-MMM-yyyy hh:mm a 'EST'");
ZoneId istZoneId = ZoneId.of("Asia/Calcutta");
ZoneId estZoneId = ZoneId.of("America/New_York");

Instant instant = Instant.now() ;
ZonedDateTime zdt = ZonedDateTime.now( estZoneId) ;
ZonedDateTime currentISTime = instant.atZone(istZoneId);                //India time
ZonedDateTime currentESTime = zdt.withZoneSameInstant(estZoneId);       //EST Time         

System.out.println("est time.............."+estFormat.format(currentESTime)); 
deHaar
  • 17,687
  • 10
  • 38
  • 51
  • Is this code executed on different machines in different locales or is it backend code and the frontend may define the local / time zone? – deHaar Nov 26 '19 at 10:02
  • yes,this code is executed on different machines in different locales and it is a backend code. Frontend is not defining any time zone. – Anjali Singh Nov 26 '19 at 10:20
  • Have you tried to get the date-time in UTC only and convert it when/as desired? You can use the system default time zone as well: `ZonedDateTime zdt = ZonedDateTime.now(ZoneId.systemDefault());` if you want it directly. – deHaar Nov 26 '19 at 10:22
  • 1
    You're there already. What happens if you print `currentISTime`? Only don't hardcode `EST` in your formatter. Use pattern letter `zzz` to print the appropriate time zone abbreviation. – Ole V.V. Nov 26 '19 at 10:26

3 Answers3

2

Make use of ZoneId.systemDefault():

public static void main(String[] args) {
    // take the instant
    Instant instant = Instant.now();
    // use it in system default time zone
    ZonedDateTime zdt = instant.atZone(ZoneId.systemDefault());
    // then in Asia/Calcutta
    ZonedDateTime currentISTime = instant.atZone(ZoneId.of("Asia/Calcutta"));
    // and in America/New York
    ZonedDateTime currentESTime = zdt.withZoneSameInstant(ZoneId.of("America/New_York"));
    // then print them all using the ISO format for zoned date times
    System.out.println("System default:\t" + zdt.format(DateTimeFormatter.ISO_ZONED_DATE_TIME));
    System.out.println("EST:\t\t" + currentISTime.format(DateTimeFormatter.ISO_ZONED_DATE_TIME));
    System.out.println("IST:\t\t" + currentESTime.format(DateTimeFormatter.ISO_ZONED_DATE_TIME));
}

On my system, this prints

System default: 2019-11-26T12:19:18.865+01:00[Europe/Berlin]
EST:            2019-11-26T16:49:18.696+05:30[Asia/Calcutta]
IST:            2019-11-26T06:19:18.865-05:00[America/New_York]

Find out what it does on yours and the remaining related ones. That's quite dynamical by relying on the system default (which may be manipulated under circumstances).

deHaar
  • 17,687
  • 10
  • 38
  • 51
1

ZoneId with ZonedDateTime is what you want.

ZoneId zoneId = ZoneId.systemDefault();
Locale locale = Locale.getDefault();

You could offer a switch, which is useful for development too:

Set<String> availableZoneIds = ZoneId.getAvailableZoneIds();
Locale[] availabelLocales = Locale.getAvailableLocales();

Adding your own Locale might sometimes be required, especially for small countries or Esperanto. It requires some effort.

Usage of ZonedDateTime for the default:

ZonedDateTime zdt = ZonedDateTime.now();

A localized date/time/date-time formatting: DateTimeFormatter:

DateTimeFormatter.ofLocalizedDateTime(FormatStyle.LONG).withLocale(Locale.FRANCE);

(withLocale should you want to use a specific locale.)

Needless to say store all as universal coordinated time, Z, or ZoneId.of("UTC").

Joop Eggen
  • 107,315
  • 7
  • 83
  • 138
0

Indeed if you define your zone as EST, this is the date you will always display. In fact it is a bad practice to use Instant.now() or any Date classes with only now. Either you pass a ZoneId as you do, or if you want to generify you use a Clock.

But to be able to change the zone depending on where you are is also a bad practice. You should always (in backend applications) use UTC dates, as outputs and inputs, and so define a Clock with something like this:

@Configuration
public class ClockConfiguration {

    @Bean
    public Clock domainClock() {
        return Clock.systemUTC();
    }

}

You could then inject the clock where needed and use Instant.now(clock).

But it should be of the responsibility of the frontend to display the date on the user timezone, and so you should only use UTC dates in your application.

If you really wanted to define a different clock on each of your server depending on their location (which I really not advise!!) you can in your code use .now() method on every date object and change the zone of the physical server to put it in the wanted timezone. The now would then use the local timezone of the server and it should work, and then remove every use of zone in your code (although it could lead to terrible mistakes in your database as date would eventually conflicts).

A Le Dref
  • 422
  • 3
  • 7