-2

Below is a Java POJO in my application:

public class Appointment {

    private Date appointmentStartDatetime;

    private String timezone;

    //...
}

Example values for these 2 properties are:

2021-10-06 05:30:00
"America/New_York"

appointmentStartDatetime represents the appointment start time in its declared timezone - i.e. the appointment starts at 5.30 in New York.

I want to convert this to a UTC date.

Is the below correct in order to do so?

 public static Date dateToUTC(Date date, String timezoneId){

        Calendar calendar = Calendar.getInstance();
        TimeZone timeZone = TimeZone.getTimeZone(timezoneId);
        calendar.setTimeZone(timeZone);

        return new Date(date.getTime() - calendar.getTimeZone().getOffset(date.getTime()));
    }

The method would be called as follows:

Date utcDate = dateToUTC(appointment.getEventStartDatetime(),appointment.getTimezone())
oguz ismail
  • 1
  • 16
  • 47
  • 69
java12399900
  • 1,485
  • 7
  • 26
  • 56
  • No my question is a bit more specific than that regarding the timezone property etc. thanks – java12399900 Jan 07 '21 at 11:32
  • 2
    You have misunderstood the meaning of `java.util.Date`. It is always related to UTC-offset that means its method `getTime()`refers to UTC. Your method `dateToUTC(…)` changes the value of `Date`-input by subtraction of an offset which is NOT okay. Just leave your `Date`-variable unchanged. Maybe you think of the output of `Date.toString()` whose dependency on local time zone confuses you. – Meno Hochschild Jan 07 '21 at 13:37
  • why would I leave my date variable unchanged? I want the output date to be in UTC, and curerntly it represents a time in a specific timezone – java12399900 Jan 07 '21 at 13:49
  • 2
    Still misunderstanding. `java.util.Date` is always UTC nothing else if you consider its millis-since-1970-value. No need to change it. And this value is independent from time zone. You need the zone only for the local representation in terms of year-month-day-hour-minute. The new (and better) `java.time`-API defines new types for this purpose, for example `LocalDateTime` which can be inferred from an instant using a time zone.. – Meno Hochschild Jan 07 '21 at 14:03
  • 1
    I recommend you don’t use `Date` and `Calendar`. Those classes are poorly and confusingly designed and long outdated. It seems that you have also let yourself confuse by them since, as has been said, your post and comments contain some misunderstandings. Instead use `ZonedDateTime` from [java.time, the modern Java date and time API](https://docs.oracle.com/javase/tutorial/datetime/). – Ole V.V. Jan 07 '21 at 14:05
  • 1
    Note that "2021-10-06 05:30:00" isn't a useful description of a `java.util.Date` value. As I mentioned in one of your earlier questions, identifying the exact instant (potentially by calling `getTime()` and reporting the millisecond value returned) is a much better approach to avoid any confusion. – Jon Skeet Jan 07 '21 at 15:14
  • 1
    In terms of understanding `java.util.Date` correctly, I have a blog post you might find useful: https://codeblog.jonskeet.uk/2017/04/23/all-about-java-util-date/ – Jon Skeet Jan 07 '21 at 15:14

2 Answers2

2

java.time

To avoid confusion use ZonedDateTime from java.time, the modern Java date and time API, for your date and time with time zone.

public class Appointment {

    private ZonedDateTime appointmentStartDateTime;
    
    // Constructor, etc.

    public Instant getUtcDateTime() {
        return appointmentStartDateTime.toInstant();
    }
    
}

Try it out:

        Appointment myAppointment = new Appointment(
                ZonedDateTime.of(2021, 1, 10, 5, 30, 0, 0,
                        ZoneId.of("America/New_York")));
        
        System.out.println(myAppointment.getUtcDateTime());

Output is:

2021-01-10T10:30:00Z

A ZonedDateTime is a date and time in a time zone. So you need only this one field instead of the two you had, appointmentStartDatetime and timezone. An Instant is a point in time independent of time zone. It prints in UTC, denoted by the trailing Z of the output above. And the conversion from ZonedDateTime to Instant is a matter of a simple method call.

Link

Oracle tutorial: Date Time explaining how to use java.time.

Ole V.V.
  • 81,772
  • 15
  • 137
  • 161
  • This answer guides you in the right direction. After going through this answer, I can say that even though my answer has some added features, this answer is just sufficient for your basic requirements. – Arvind Kumar Avinash Jan 07 '21 at 16:32
  • @LiveandLetLive Thank you for the reading guide, I believe it’s helpful. And thanks for posting your answer, there’s a *wealth* of good information in it. – Ole V.V. Jan 07 '21 at 22:30
1

The java.util.Date object is not a real date-time object like the modern date-time types; rather, it represents the number of milliseconds since the standard base time known as "the epoch", namely January 1, 1970, 00:00:00 GMT (or UTC). When you print an object of java.util.Date, its toString method returns the date-time in the JVM's timezone, calculated from this milliseconds value. If you need to print the date-time in a different timezone, you will need to set the timezone to SimpleDateFormat and obtain the formatted string from it.

Note that the date-time API of java.util and their formatting API, SimpleDateFormat are outdated and error-prone. It is recommended to stop using them completely and switch to the modern date-time API.

Using the modern date-time API:

import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.Month;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;

class Appointment {
    private LocalDateTime appointmentStartDatetime;
    private String timezone;

    public Appointment(LocalDateTime appointmentStartDatetime, String timezone) {
        this.appointmentStartDatetime = appointmentStartDatetime;
        this.timezone = timezone;
    }

    public LocalDateTime getAppointmentInLocalDateTime() {
        return appointmentStartDatetime;
    }

    public Instant getAppointmentInUTC() {
        return appointmentStartDatetime.toInstant(ZoneOffset.UTC);
    }

    public ZonedDateTime getAppointmentInZonedDateTime() {
        return appointmentStartDatetime.atZone(ZoneId.of(timezone));
    }

    public ZonedDateTime getAppointmentInZdtAnotherTimeZone(String timezone) {
        return getAppointmentInZonedDateTime().withZoneSameInstant(ZoneId.of(timezone));
    }
    // ...
}

public class Main {
    public static void main(String[] args) {
        Appointment appointment = new Appointment(
                LocalDateTime.of(LocalDate.of(2020, Month.FEBRUARY, 15), LocalTime.of(10, 30)), "America/New_York");

        System.out.println(appointment.getAppointmentInLocalDateTime());
        System.out.println(appointment.getAppointmentInUTC());
        System.out.println(appointment.getAppointmentInZonedDateTime());
        System.out.println(appointment.getAppointmentInZdtAnotherTimeZone("Asia/Calcutta"));
    }
}

Output:

2020-02-15T10:30
2020-02-15T10:30:00Z
2020-02-15T10:30-05:00[America/New_York]
2020-02-15T21:00+05:30[Asia/Calcutta]
  1. An Instant represents an instantaneous point on the time-line.
  2. A ZonedDateTime holds state equivalent to three separate objects, a LocalDateTime, a ZoneId and the resolved ZoneOffset. The function, ZonedDateTime#withZoneSameInstant returns a copy of this date-time with a different time-zone, retaining the instant.

Given below is an overview of the Java SE 8 date-time types:

enter image description here

Learn more about the modern date-time API from Trail: Date Time.

Arvind Kumar Avinash
  • 71,965
  • 6
  • 74
  • 110