4

I'm trying to parse date like this:

DateFormat df = new SimpleDateFormat("MMM dd, yyyy K:mm:ss,SSS a z", Locale.ENGLISH);
Date date = df.parse("Oct 04, 2015 2:11:58,757 AM UTC");

And I'm getting a value of 5 hours am, because i live in UTC+3 timezone. But i need to have value of 2am, however, with the same format string(date string given in a specified format, which i'm not allowed to change). How to do this?

Upd: I don't need to format the date in proper timezone, i need to COMPARE these dates by its values without timezones. I want exactly that date have parsed ignoring the timezone in original string - and be always in the same timezone (my, for example), no matter what contains original string: UTC or UTC+3 or something else.

sandwwraith
  • 299
  • 1
  • 2
  • 10
  • 2
    A `Date` has no timezone. It represents a timestamp. Format it with the appropriate time zone. – Sotirios Delimanolis Oct 12 '15 at 22:37
  • 1
    Try removing the "UTC" from the date. UTC gives the specific timezone different from yours, while you want the date to be handled as if specified in your local timezone – MTilsted Oct 12 '15 at 22:41
  • Set the time zone of df: df.setTimeZone(TimeZone.getTimeZone("UTC")); Note that Date#toString uses the default time zone. – Pinkie Swirl Oct 12 '15 at 22:43
  • No, the parser definitely does not _produce it_. Your `Date` object is one that represents `Oct 04, 2015 2:11:58,757 AM UTC`, which is the same moment as `Oct 04, 2015 2:11:58,757 AM UTC+3`. If you want to display your date differently, `format` it with the appropriate time zone. – Sotirios Delimanolis Oct 12 '15 at 22:44
  • I need to parse string with "UTC" ("z" in format string) due to format specifies, but i also need to get all dates in original (without converting timezones) state. And i don't need to print(format) it, i need these dates to compare it with others, which can be parsed in different format without any info of timezone. – sandwwraith Oct 12 '15 at 22:45
  • I don't think this is duplicate that suggested. Anyway your parsing logic is correct. You got the correct date. If you want to display it in any timezone, the typical use is in conjunction of Calendar: Calendar cal = Calendar.getInstance();] cal.setTimeZone(TimeZone.getTimeZone("Europe/London")); cal.setTime(date); System.out.println(cal.get(Calendar.HOUR)); – zdenda.online Oct 12 '15 at 22:46
  • You need to understand that in date you have correct time and now u only need some printing logic that will show hours in your desired timezone (using calendar as in previous comment) – zdenda.online Oct 12 '15 at 22:47
  • 1
    Again, `Date` is a timestamp, a number of milliseconds since unix epoch. It has no concept of timezone. – Sotirios Delimanolis Oct 12 '15 at 22:48
  • I guess the error comes from something like System.out.print(date), which calls the toString method of date, which uses a formatter with the default time zone. As stated above, Date itself is "timezoneless". – Pinkie Swirl Oct 12 '15 at 22:50
  • I understood that `Date` just a number of milliseconds, but parser gives me a different amount of these in different timezones – sandwwraith Oct 12 '15 at 22:50
  • Please edit your question to demonstrate what you mean. – Sotirios Delimanolis Oct 12 '15 at 22:51
  • @SotiriosDelimanolis You are wrong. These times are NOT the same moment. Actually 2:11 UTC and 5:11 UTC+3 are the same moment – zdenda.online Oct 12 '15 at 22:52
  • @d1x Your last sentence is exactly what I'm saying. – Sotirios Delimanolis Oct 12 '15 at 22:52
  • What you're doing now is completely contradictory to what you're saying you want to do. – Sotirios Delimanolis Oct 12 '15 at 22:57
  • Ad Upd2. Your solution is incorrect... Maybe it prints 2am but only because you moved the time manually so it conforms your timezone. Instead of saying 2am UTC is 5am my time or 3am UTC+1, you are saying 2am UTC = 2am UTC+3 – zdenda.online Oct 12 '15 at 22:58
  • 1
    I'm sorry you've misunderstood me, but i want exactly that date have parsed ignoring the timezone in original string - and be always in the same timezone (my, for example), no matter what contains original string: UTC or UTC+3 or something else. – sandwwraith Oct 12 '15 at 23:07
  • That's an entirely different question. Edit your question (or ask a new one) explaining that you want to parse a date String given in a specific format, ignoring the timezone identifier. – Sotirios Delimanolis Oct 12 '15 at 23:11
  • If you solved your own question, post the answer as an actual answer to your question! You can answer your own question on stack overflow, and now that you've found it, you should share it in case others come here with the same problem - the best way to do it is with the format of Q&A, rather than editing your question. – snickers10m Oct 13 '15 at 01:10

2 Answers2

11

The accepted Answer is working too hard. Manipulating offsets is the province of a date-time library. Doing such work yourself is a waste of your time, and likely to be a source of bugs.

The old java.util.Date/.Calendar classes are notoriously troublesome. Avoid them. Instead use either java.time or Joda-Time.

java.time

Java 8 and later has a new java.time framework built-in.

Confused Question

Your Question is confused. You say you want to ignore time zone, yet you accept an answer that does indeed parse and process the time zone. And that answer then adjusts the result by an offset. So, it seems that you do not want to ignore the time zone.

Indeed, ignoring the time zone rarely makes sense. Perhaps you want to compare a pair of factories in Berlin and in Detroit to see if they both take a lunch break at the same time. In this case you are comparing their respective wall-clock time. The java.time framework offers the “Local” classes for this purpose: LocalDate, LocalTime, and LocalDateTime. But this is rarely needed in most business scenarios in my experience. These objects are not tied to the timeline.

So it seems that what you do want is to be able to compare date-time values across various time zones. The java.time classes do that implicitly. ZonedDateTime objects with various assigned time zones can be compared to one another with isBefore, isAfter, and isEqual methods.

Example Code

First we parse the input string.

The z pattern code means to expect and parse a time zone. The resulting date-time object will also be assigned this object if no other specific time zone is specified.

We also assign a Locale object with a human language component matching the text we expect to see in the input string. In this case, we need any Locale with English.

String input = "Oct 04, 2015 2:11:58,757 AM UTC";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern( "MMM dd, yyyy K:mm:ss,SSS a z" ).withLocale( Locale.ENGLISH );

ZonedDateTime then = ZonedDateTime.parse( input, formatter );

Next we get the current time for Québec. This arbitrary choice of time zone will demonstrate further below that we can compare this ZonedDateTime object to another with a different time zone. Specifically, comparing against the UTC time zone assigned to our then object above.

ZoneId zoneId = ZoneId.of( "America/Montreal" );
ZonedDateTime now = ZonedDateTime.now( zoneId );

Do the comparison.

Boolean isThenBeforeNow = then.isBefore( now );

By the way, generally-speaking, the best practice in date-time work is to convert all your date-time values to UTC time zone for business logic, storage, and data exchange. Adjust into a time zone only as need be to satisfy a user’s expectations on-screen or in reports.

ZonedDateTime nowUtc = now.withZoneSameInstant( ZoneOffset.UTC );

Dump to console.

System.out.println( "input: " + input );
System.out.println( "then: " + then );
System.out.println( "now: " + now );
System.out.println( "isThenBeforeNow: " + isThenBeforeNow );
System.out.println( "nowUtc: " + nowUtc );

When run.

input: Oct 04, 2015 2:11:58,757 AM UTC

then: 2015-10-04T02:11:58.757Z[UTC]

now: 2015-10-19T19:28:04.619-04:00[America/Montreal]

isThenBeforeNow: true

nowUtc: 2015-10-19T23:28:04.619Z


About java.time

The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.

To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.

You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.

Where to obtain the java.time classes?

The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.

Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
2

Upd2: Solved

Okay, now i get what i want:

DateFormat df = new SimpleDateFormat("MMM dd, yyyy K:mm:ss,SSS a z", Locale.ENGLISH);
Date date = df.parse("Oct 04, 2015 2:11:58,757 AM UTC");
long diff = TimeZone.getDefault().getRawOffset() - df.getTimeZone().getRawOffset();
date = new Date(date.getTime()-diff);

Anyway, thanks for everyone

sandwwraith
  • 299
  • 1
  • 2
  • 10