33

I want to get the current time in UTC. What I do so far is following (just for testing purposes):

    DateTime dt = new DateTime();
    DateTimeZone tz = DateTimeZone.getDefault();
    LocalDateTime nowLocal = new LocalDateTime();
    DateTime nowUTC = nowLocal.toDateTime(DateTimeZone.UTC);

    Date d1 = nowLocal.toDate();
    Date d2 = nowUTC.toDate();

    L.d("tz: " + tz.toString());
    L.d("local: " + d1.toString());
    L.d("utc: " + d2.toString());
  • d1 is my local time, that's fine
  • d2 is my local time + 1, but should be local time - 1...

My local time zone is UTC+1 (according to the debug output and the list here: https://www.joda.org/joda-time/timezones.html)...

How do I correctly convert from one time zone to another (inclusive the millisecond representation)?

EDIT

I need the date/milliseconds... It's NOT about displaying the time correctly....

EDIT 2

Now, with the help of a comment and an answer, I tried following:

    DateTimeZone tz = DateTimeZone.getDefault();
    DateTime nowLocal = new DateTime();
    LocalDateTime nowUTC = nowLocal.withZone(DateTimeZone.UTC).toLocalDateTime();
    DateTime nowUTC2 = nowLocal.withZone(DateTimeZone.UTC);

    Date dLocal = nowLocal.toDate();
    Date dUTC = nowUTC.toDate();
    Date dUTC2 = nowUTC2.toDate();

    L.d(Temp.class, "------------------------");
    L.d(Temp.class, "tz    : " + tz.toString());
    L.d(Temp.class, "local : " + nowLocal +     " | " + dLocal.toString());
    L.d(Temp.class, "utc   : " + nowUTC +       " | " + dUTC.toString()); // <= WORKING SOLUTION
    L.d(Temp.class, "utc2  : " + nowUTC2 +      " | " + dUTC2.toString());

OUTPUT

tz    : Europe/Belgrade
local : 2015-01-02T15:31:38.241+01:00 | Fri Jan 02 15:31:38 MEZ 2015
utc   : 2015-01-02T14:31:38.241 | Fri Jan 02 14:31:38 MEZ 2015
utc2  : 2015-01-02T14:31:38.241Z | Fri Jan 02 15:31:38 MEZ 2015

What I wanted was, that the local date displays 15 o'clock and utc date displays 14 o'clock... For now, this seems to work...

----- EDIT3 - Final solution -----

Hopefully, this is a good solution... I think, i respects all tipps i got...

    DateTimeZone tz = DateTimeZone.getDefault();
    DateTime nowUTC = new DateTime(DateTimeZone.UTC);
    DateTime nowLocal = nowUTC.withZone(tz);

    // This will generate DIFFERENT Dates!!! As I want it!
    Date dLocal = nowLocal.toLocalDateTime().toDate();
    Date dUTC = nowUTC.toLocalDateTime().toDate();

    L.d("tz    : " + tz.toString());
    L.d("local : " + nowLocal +     " | " + dLocal.toString());
    L.d("utc   : " + nowUTC +       " | " + dUTC.toString());

Output:

tz    : Europe/Belgrade
local : 2015-01-03T21:15:35.170+01:00 | Sat Jan 03 21:15:35 MEZ 2015
utc   : 2015-01-03T20:15:35.170Z | Sat Jan 03 20:15:35 MEZ 2015
JodaStephen
  • 60,927
  • 15
  • 95
  • 117
prom85
  • 16,896
  • 17
  • 122
  • 242
  • I think this should provide the answer you are looking for http://stackoverflow.com/questions/11629936/joda-time-different-between-timezones. – kentsurrey Jan 02 '15 at 11:25

7 Answers7

86

You're making it far more complicated than you need to:

DateTime dt = new DateTime(DateTimeZone.UTC);

No conversion required at all. If you find you actually need to convert, you can use withZone. I'd suggest you avoid going via LocalDateTime, however, as that way you can lose information due to time zone transitions (two different instants can have the same local time in the same time zone, because clocks go back and repeat local time.

Having said all of this, for the sake of testability I personally like using a Clock interface which allows me to get the current time (e.g. as an Instant). You can then use dependency injection to inject a real system clock when running in production, and a fake clock with a preset time for tests. Java 8's java.time package has this idea built into it, btw.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • Could you take a look on my edit 2? I tried your approach (i think), but it still does not work... – prom85 Jan 02 '15 at 13:21
  • 1
    @prom85: It's not clear why you're converting to `Date`, what your actual output is, or what your expected output is. Bear in mind that `Date.toString()` *always* uses the system default time zone... you may well just be confused by the output there. I would suggest avoiding using `Date` as far as possible. – Jon Skeet Jan 02 '15 at 13:29
  • I will try `withZoneRetainFields`... this seems to be what I want... It changes the milliseconds as well and does not preserve that data... What I want is to save the dates in a local database and to compare values to dates from online resources... – prom85 Jan 02 '15 at 13:30
  • 1
    @prom85: You don't want `withZoneRetainFields`, but again, it sounds like the problem is elsewhere - I suspect it's with how you're saving the value to the database. Without knowing *anything* about the database (this is the first mention of it) it's hard to help you. – Jon Skeet Jan 02 '15 at 13:32
  • Actually, it does not matter that I want to save the value in a database... For testing, I'm trying to create `java.util.Date` objects that represent the current time in UTC and in my local time... That's all... – prom85 Jan 02 '15 at 13:34
  • 2
    @prom85: It really *does* matter, because your "testing" is broken, and may be completely irrelevant to what you're really trying to do. There's no such concept of a `java.util.Date` in a particular time zone. The `Date` class *only* stores a point in time. It doesn't know which time zone you're interested in. The concept of a "`java.util.Date` object representing the current time in your local time zone" is a non-sequitur, just like saying "I want to have an `int` storing my age in hex" - an `int` doesn't have a format, just like a `Date` doesn't have a time zone. – Jon Skeet Jan 02 '15 at 13:37
  • but it does represent an milliseconds offset to 01.01.1970... That's the format that mysql for example uses... And many java libraries use Dates... And I just want to convert such dates from one timezone to another... That's my usecase at the end... I store `java.util.Date` directly to a mysql database and the online storage I use uses the same data structure... I want to share data between users, so it is important, that all users upload their data in the same "time zone"... As i want to receive data that was created after a special date... Or similar things... – prom85 Jan 02 '15 at 13:42
  • 2
    @prom85: I don't think you've read my comment properly. The idea of converting a `java.util.Date` from one time zone to another is nonsensical, because a `java.util.Date` doesn't *have* a time zone. It's not clear where users uploading their data comes in here, but you really need to understand the core point about `Date` not having a time zone before anything else. – Jon Skeet Jan 02 '15 at 13:44
  • I understand that... What I want is ONE number, that is comparable. I dont care, which timezone, actually... I just want to convert all datetimes to a unified comparable number, that's all. And for the sake of easyness, I would, let's call it represent, all datetimes as UTC times and save the UTC time offset to 01.01.1970 as a number wherever I want... For displaying, I can always relate this number to a timezone again... – prom85 Jan 02 '15 at 13:49
  • 1
    @prom85: Okay, so you convert whatever you get into a `Date`, and it should be fine. To get the *current* time, you can just use `new Date()` and not worry about anything else. It's still not clear what the problem is - particularly as you still haven't explained what you mean by "does not work". As I said before, you should state the expected output and the actual output. – Jon Skeet Jan 02 '15 at 13:51
  • Actually, I found a solution now... I think, I get what you wanted to explain... i probably would never need `Dates` if I always use `DateTimes`. I still need conversions between date and DateTime because I will have to convert my existing data... Because at the moment I saved local Dates... I found out, that LocalDateTime is just a time without a timezone... So after convert `DateTimes` with the by you mentioned `withZone` I can convert this `DateTime` to a `LocalDateTime`... And afterwards, I can convert this `LocalDateTime` to a `java.util.Date`... – prom85 Jan 02 '15 at 14:27
  • @prom85: Why are you converting to `LocalDateTime` at all? Just use `DateTime.toDate`. – Jon Skeet Jan 02 '15 at 14:28
  • As we are the only ones discussing, I edited my second edit again... With my current test and with a working example... As you can see, without using `LocalDateTime`, the `toDate` function does not behave as I want it... – prom85 Jan 02 '15 at 14:36
  • 2
    @prom85: Well as I've said before, your expectation of getting different results for `Date` values representing the same point in time is impossible. You're also calling `LocalDateTime.toDate` without specifying a time zone - and *that's* not a good idea. But it's still not clear why none of your sample code uses the code in my answer, i.e. `new DateTime(DateTimeZone.UTC)`. It's not clear why you care about the system local time zone at all, to be honest. I'm afraid I'm not going to be able to help much more today, but I think you really need to think carefully about your requirements. – Jon Skeet Jan 02 '15 at 14:55
  • 1
    @JonSkeet +1 for your simple answer and comments, I assume the OP has a formatting problem?! – Meno Hochschild Jan 02 '15 at 15:23
  • I think, my new solution respects your tipps... So far, I understood that I should base all my logic on utc times to be safe and just convert it for displaying the datetime... And that I should always explicitly should set the timezone to use... Thanks for your detailed and patient answers. – prom85 Jan 03 '15 at 20:27
  • 1
    @prom85: Well it depends on the exact situation, but yes, very often it makes sense to use UTC everywhere except for displaying the values to users. Whether you use *their* time zone or some time zone specific to the event in question depends on the app though. – Jon Skeet Jan 03 '15 at 20:57
15

You can also use the static method now which makes it even more readable

DateTime.now(DateTimeZone.UTC)
JodaStephen
  • 60,927
  • 15
  • 95
  • 117
Kobynet
  • 983
  • 11
  • 23
12

Use this

DateTime.now().withZone(DateTimeZone.UTC)

and if you want to format, you can use

DateTime.now().withZone(DateTimeZone.UTC).toString("yyyyMMddHHmmss")
David
  • 2,987
  • 1
  • 29
  • 35
Naidu
  • 245
  • 1
  • 4
  • 13
3

Please try to listen to Jon Skeets good advise and comments. Here an additional explanation. Your edit-2 contains a mistake:

DateTimeZone tz = DateTimeZone.getDefault();
DateTime nowLocal = new DateTime();
LocalDateTime nowUTC = nowLocal.withZone(DateTimeZone.UTC).toLocalDateTime();
DateTime nowUTC2 = nowLocal.withZone(DateTimeZone.UTC);

Date dLocal = nowLocal.toDate();
Date dUTC = nowUTC.toDate();
Date dUTC2 = nowUTC2.toDate();

If you call toDate() on an object nowUTC of type LocalDateTime then you can get surprises - see javadoc. Joda-Time claims to use the same fields in java.util.Date as in nowUTC. What does this mean? Let's analyze:

nowUTC.toString() produces 2015-01-02T14:31:38.241 That is without timezone (note the missing Z at the end), so it is just a plain local timestamp. By context, we know it was generated in UTC. In your next step however, you convert it to a java.util.Date using the mentioned method above. This method combines the local timestamp with the system timezone (Belgrade) PRESERVING the FIELDS, hence CHANGING the instant. So you have finally miscorrected your instant. And your second line is wrong.

If you just want

utc date displays 14 o'clock

then don't use the questionable and misleading conversion method Joda-Time offers. Use instead a dedicated formatter with the pattern "EEE MMM dd HH:mm:ss zzz yyyy" or similar (Joda-Time offers DateTimeFormatter). Set the UTC-offset on this formatter and print. Done. Abandon completely any call of java.util.Date.toString(). This way, you don't even need to do any dangerous conversion at all.

Meno Hochschild
  • 42,708
  • 7
  • 104
  • 126
2

From here: http://www.joda.org/joda-time/userguide.html#Changing_TimeZone

// get current moment in default time zone
DateTime dt = new DateTime();
// translate to London local time
DateTime dtLondon = dt.withZone(DateTimeZone.forID("Europe/London"));

The resulting value dtLondon has the same absolute millisecond time, but a different set of field values.

You can substitute `Europe/London' for the timezone you want (UTC). See this list of proper time zone names.

Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
Greg Kopff
  • 15,945
  • 12
  • 55
  • 78
0
    SimpleDateFormat sdf = new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss" );
    // or SimpleDateFormat sdf = new SimpleDateFormat( "MM/dd/yyyy KK:mm:ss a Z" );
    sdf.setTimeZone( TimeZone.getTimeZone( "UTC" ) );
    System.out.println( sdf.format( new Date() ) 

);

Instead of System.out.println( sdf.format( new Date() ) put your local date

LONGHORN007
  • 526
  • 9
  • 24
  • I edited my question... I need the date/milliseconds... Displaying the date correctly is not enough... Thanks though – prom85 Jan 02 '15 at 11:23
0

I fixed this with this converter

public class DateTimeConverter implements AttributeConverter<DateTime, Date> {
    @Override
    public Date convertToDatabaseColumn(DateTime attribute) {
        return attribute == null ? null
                : new Date(attribute
                        .withZone(DateTimeZone.UTC)
                        .withZoneRetainFields(DateTimeZone.getDefault())
                        .getMillis());
    }

    @Override
    public DateTime convertToEntityAttribute(Date dbData) {
        return dbData == null ? null
               : new DateTime(dbData.getTime())
                        .withZoneRetainFields(DateTimeZone.UTC)
                        .withZone(DateTimeZone.getDefault());
    }
}

Dates are stored as UTC and recovered with your current time zone

Wicowyn
  • 11
  • 1
  • 6