-1

I want to store UTC time in DB (yyyy-mm-dd or dd-mm-yyyy)

  1. I want to convert local time zone to UTC and store it in DB

I tried in different ways but that is not working properly. Below is my code for convert local to UTC

  1. get the UTC time from DB and convert to local timezone

Below is my code for both:

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;

public class TestDate {

    public static void main(String[] args) {                
        /*Date de = new Date();
        DateFormat converter1 = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
        System.err.println(converter1.format(de));
        Date der =*/
                localToGMT();
//          System.err.println("0000 : "+converter1.format(der));
        Date d=  new Date("09/10/2017 21:53:17");
        gmttoLocalDate(d);
    }

    public static Date localToGMT() {
//      Date gmt = new Date(sdf.format(date));
        Date gmt = null;
        Date localTime =  new Date();
         //creating DateFormat for converting time from local timezone to GMT
         DateFormat converter = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");

         //getting GMT timezone, you can get any timezone e.g. UTC
         converter.setTimeZone(TimeZone.getTimeZone("GMT"));
         System.out.println("local time : " + localTime);;
         System.out.println("time in GMT : " + converter.format(localTime));

         try {
            gmt =converter.parse((converter.format(localTime)));
        } catch (ParseException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
         /*Date date = new Date("2017/10/10 12:04:28");
         System.err.println(date);
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
            sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
        gmt = sdf.parse(sdf.format(date));*/
        System.err.println("converted to utc :" + gmt);
        return gmt;
    }

    public static Date gmttoLocalDate(Date date) {
        String timeZone = Calendar.getInstance().getTimeZone().getID();
        Date local = new Date(date.getTime() + TimeZone.getTimeZone(timeZone).getOffset(date.getTime()));
        System.err.println("converted to local timezone :" + local);
        return local;
    }
}
shiv
  • 21
  • 1
  • 8
  • A `Date` has [no format, nor any timezone information](https://codeblog.jonskeet.uk/2017/04/23/all-about-java-util-date). Is the database field a date/timestamp or a string/text/varchar type? –  Oct 11 '17 at 12:32

2 Answers2

4

A java.util.Date has no timezone information. It has only a long value, which is the number of milliseconds since unix epoch (which is 1970-01-01T00:00:00Z or January 1st 1970 at midnight in UTC). This value (number of milliseconds since epoch) has many names, I'll just call it timestamp for short.

The timestamp is an "absolute" value, it's the same everywhere in the world.
Example: I've just got the current time (System.currentTimeMillis()) and the result was 1507722750315 (that's the current number of milliseconds since epoch). This value is the same for everyone in the world. But this same value can correspond to a different date/time in each timezone:

  • in UTC, it corresponds to 2017-10-11T11:52:30.315Z
  • in São Paulo (Brazil), it's 2017-10-11T08:52:30.315-03:00
  • in London, it's 2017-10-11T12:52:30.315+01:00
  • in Tokyo, it's 2017-10-11T20:52:30.315+09:00
  • in India, it's 2017-10-11T17:22:30.315+05:30
  • in Auckland, it's 2017-10-12T00:52:30.315+13:00 (it's already "tomorrow" there)
  • and so on...

So, when you do a method that receives a java.util.Date and tries to convert it to another java.util.Date, you're not converting anything. The Date contains only the timestamp value (the "absolute" value that corresponds to a specific point in time). But the Date itself doesn't know anything about timezones, so it's pointless to do such convertion (the timestamp is the same for the whole world, there's no need to convert it).


"But when I print the date, I see the value in my local time"

Well, this is explained in this article. If you System.out.println a Date, or log it, or look its value in a debugger, you'll see something like:

Wed Oct 12 12:33:99 IST 2017

But that's because the toString() method is being implicity called, and this method converts the timestamp value to the JVM default timezone (so it looks like a "local date/time").

But remember, this Wed Oct etc string is not the actual value hold by the Date object: all it has is the timestamp that corresponds to that date/time displayed. But the date object itself doesn't has any notion of local date/time, nor any timezone related information. What you see is just a representation of the timestamp value, in a specific format, for a specific timezone.


What to do then?

If the database field is a date type, then the JDBC driver usually handles it, so you just save the Date object directly. There's no need to care about formats and timezones, because the Date has no format, nor any timezone information.

The problem with date types is that any language/database/vendor/application shows it in a different way. Java's Date.toString() converts it to the JVM default timezone, some databases shows in a specific format (dd/mm/yyyy, or yyyy-mm-dd, etc) and converts to whatever timezone configured in the DB, and so on.

But remember that a date itself has no format. It has just a value, the thing is that the same date can be represented in different formats. Example: October 15th 2017 can be represented as 2017-10-15, 10/15/2017, 15th Oct 2017, 15 de Outubro de 2017 (in pt_BR (portuguese) locale) and so on. The format (the representation) is different, but the Date value is the same.

So, if you're dealing with Date objects, the database field is a date-related type and it returns and saves the Date object, just use it directly.


If you want to display this date, though, (show to an user, or log it), or if the database field is a String (or a varchar, or any other text-related type), then it's a completely different matter.

When printing a date (or converting it to a String), you can choose the format and the timezone you're converting to, using a SimpleDateFormat:

// a java.util.Date with the same timestamp above (1507722750315)
Date date = new Date(1507722750315L);
// choose a format
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
// choose a timezone to convert to
sdf.setTimeZone(TimeZone.getTimeZone("Asia/Kolkata"));
// convert to a String
String formattedDate = sdf.format(date);
System.out.println(formattedDate); // 2017-10-11 17:22:30

In this case, the output is:

2017-10-11 17:22:30

If I change the timezone to another one, the result will be converted to it:

sdf.setTimeZone(TimeZone.getTimeZone("Europe/London"));
// convert to a String
String formattedDate = sdf.format(date);
System.out.println(formattedDate); // 2017-10-11 12:52:30

Now the result is:

2017-10-11 12:52:30

But the Date value is still the same: if you call date.getTime(), it'll return the timestamp value, which is still 1507722750315. I just changed the representation of this date (the format and the timezone). But the Date itself has its value unchanged.

Also note that I used IANA timezones names (always in the format Region/City, like Asia/Kolkata 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 TimeZone.getAvailableIDs().

You can also use the system's default timezone with TimeZone.getDefault(), but this can be changed without notice, even at runtime, so it's better to explicity use a specific one.


To get a Date from a String, don't use the deprecated constructor (new Date("09/10/2017 21:53:17")). It's better to use a SimpleDateFormat and set the timezone this date refers to.

In the tests I've made, 09/10/2017 is interpreted as "month/day/year", so I'm going to use the same. I'm also considering that the input is in UTC, but you can change it to whatever timezone you need:

String s = "09/10/2017 21:53:17";
SimpleDateFormat parser = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss");
// the input is in UTC (change it to the timezone you need)
parser.setTimeZone(TimeZone.getTimeZone("UTC"));
Date d = parser.parse(s);

The date above will be equivalent to September 10th 2017, at 21:53:17 in UTC. If the input is in another timezone, just change "UTC" by the corresponding timezone name.

Check the javadoc for all possible formats used by SimpleDateFormat.


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 6 or 7, you can use the ThreeTen Backport, a great backport for Java 8's new date/time classes. And for Android, you'll also need 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.

The newest JDBC drivers already have support to new Java 8 types (check if yours already has). But if you still need to use java.util.Date, you can easily convert from/to the new API.

In Java 8, Date has the new from and toInstant methods, to convert from/to the new java.time.Instant class:

Date date = Date.from(instant);
Instant instant = date.toInstant();

In ThreeTen Backport, you can use the org.threeten.bp.DateTimeUtils class to convert from/to org.threeten.bp.Instant:

Date date = DateTimeUtils.toDate(instant);
Instant instant = DateTimeUtils.toInstant(date);

By having an Instant, you can easily convert to whatever timezone you want (using the ZoneId class to convert it to a ZonedDateTime), and then using a DateTimeFormatter to change the format:

// convert Date to Instant, and then to a timezone
ZonedDateTime z = date.toInstant().atZone(ZoneId.of("Asia/Kolkata"));
// format it
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String formatted = fmt.format(z);
System.out.println(formatted); // 2017-10-11 17:22:30

To parse a String is similar. You use a DateTimeFormatter, then parse to a LocalDateTime (because the input String doesn't have a timezone in it), then you convert it to a timezone (and you can optionally convert it to a Date if you need):

String input = "09/10/2017 21:53:17";
DateTimeFormatter parser = DateTimeFormatter.ofPattern("MM/dd/yyyy HH:mm:ss");
// parse the input
LocalDateTime dt = LocalDateTime.parse(input, parser);
// convert to a timezone
ZonedDateTime z = dt.atZone(ZoneId.of("Asia/Kolkata"));
// you can format it, just as above

// you can also convert it to a Date
Date d = Date.from(z.toInstant());

If you want to convert to UTC, use the constant ZoneOffset.UTC instead of the ZoneId. Also, check the javadoc for more details about the formats (they're not always the same used by SimpleDateFormat).

Community
  • 1
  • 1
  • `timestamp` is quite ambiguous, with different meaning is various computing situations. I suggest calling a count of seconds/milliseconds etc from the epoch reference date a “count-from-epoch”. – Basil Bourque Oct 11 '17 at 21:32
  • This was a fantastic answer, especially the part about printing dates. – jayb0b Jan 26 '18 at 14:18
0

Local to UTC

 public static Date localToUTC() {
    Date date = new Date();
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
    sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
    Date gmt = new Date(sdf.format(date));
    return gmt;
    }

UTC to local

public static Date utctoLocalDate(Date date) {

String timeZone = Calendar.getInstance().getTimeZone().getID();
Date local = new Date(date.getTime() + TimeZone.getTimeZone(timeZone).getOffset(date.getTime()));
return local

}

vishal jangid
  • 2,967
  • 16
  • 22
  • thank you for your response. return gmt and return local are display like this wed oct 12 12:33:99 ist 2017 but response value want to store in db i want response 2017-10-12 12:54:54 – shiv Oct 11 '17 at 11:00