Showing correct time from Milliseconds with desired TimeZone

前端 未结 1 618
别那么骄傲
别那么骄傲 2021-01-18 15:01

I\'m developing an application which takes data from Google TimeZone API. Simply I have time in milliseconds of desired place on Earth.

For Example :

相关标签:
1条回答
  • 2021-01-18 15:19

    Timestamps represent an "absolute" value of a time elapsed since epoch. Your currentTimeUTCinSeconds, for example, represent the number of seconds since unix epoch (which is 1970-01-01T00:00Z, or January 1st 1970 at midnight in UTC). Java API's usually work with the number of milliseconds since epoch.

    But the concept is the same - those values are "absolute": they are the same for everyone in the world, no matter where they are. If 2 people in different parts of the world (in different timezones) get the current timestamp at the same time, they'll all get the same number.

    What changes is that, in different timezones, this same number represents a different local date and time.

    For example, the timestamp you're using, that corresponds to Sep 7th 2017 08:55:56 UTC, which value is 1504774556 (the number of seconds since epoch). This same number corresponds to 09:55 in London, 13:55 in Karachi, 17:55 in Tokyo and so on. Changing this number will change the local times for everyone - there's no need to manipulate it.

    If you want to get a java.util.Date that represents this instant, just do:

    int currentTimeUTCinSeconds = 1504774556;
    // cast to long to not lose precision
    Date date = new Date((long) currentTimeUTCinSeconds * 1000);
    

    This date will keep the value 1504774556000 (the number of milliseconds since epoch). This value corresponds to 09:55 in London, 13:55 in Karachi and 17:55 in Tokyo.

    But printing this date will convert it to your JVM default timezone (here is a good explanation about the behaviour of Date::toString() method). When you do "Date Time : "+date, it implicity calls toString() method, and the result is the date converted to your default timezone.

    If you want the date in a specific format and in a specific timezone, you'll need a SimpleDateFormat. Just printing the date (with System.out.println or by logging it) won't work: you can't change the format of the date object itself, because a Date has no format.

    I also use a java.util.Locale to specify that the month and day of week must be in English. If you don't specify a locale, it'll use the system default, and it's not guaranteed to always be English (and this can be changed, even at runtime, so it's better to always specify a locale):

    // use the same format, use English for month and day of week
    SimpleDateFormat sdf = new SimpleDateFormat("EEE MMM dd yyyy HH:mm:ss 'GMT'Z (zzzz)", Locale.ENGLISH);
    // set the timezone I want
    sdf.setTimeZone(TimeZone.getTimeZone("Europe/London"));
    // format the date
    System.out.println(sdf.format(date));
    

    The output will be:

    Thu Sep 07 2017 09:55:56 GMT+0100 (British Summer Time)

    Note that I don't need to manipulate the timestamp value. I don't use the google API, but I think their explanation is too confusing and the code above achieve the same results with less complication.

    In your specific case, you can do:

    date1.setText("Date Time : "+sdf.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.

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

    To get a date from a timestamp, I use a org.threeten.bp.Instant with a org.threeten.bp.ZoneId to convert it to a timezone, creating a org.threeten.bp.ZonedDateTime. Then I use a org.threeten.bp.format.DateTimeFormatter to format it:

    int currentTimeUTCinSeconds = 1504774556;
    // get the date in London from the timestamp
    ZonedDateTime z = Instant.ofEpochSecond(currentTimeUTCinSeconds).atZone(ZoneId.of("Europe/London"));
    // format it
    DateTimeFormatter fmt = DateTimeFormatter.ofPattern("EEE MMM dd yyyy HH:mm:ss 'GMT'XX (zzzz)", Locale.ENGLISH);
    System.out.println(fmt.format(z));
    

    The output is the same:

    Thu Sep 07 2017 09:55:56 GMT+0100 (British Summer Time)

    In your case, just do:

    date1.setText("Date Time : "+fmt.format(z));
    
    0 讨论(0)
提交回复
热议问题