SimpleDateFormat returns wrong time zone during parse

I am facing a strange problem during the creation of Date object. I have the below code to set the time zone of the date to UTC. Before the parse statement i see that sdfDate has time zone as UTC but after the parse statement i see that punchDate has value: Sat Mar 30 01:00:00 CET 2013, this i believe is coming from my system. But how do i make sure that the time zone remains same even after parse.

Date punchDate = null;
Date punchTime = null;

SimpleDateFormat sdfDate = new SimpleDateFormat("dd.MM.yyyy");
SimpleDateFormat sdfTime = new SimpleDateFormat("HH:mm:ss");

    try
    {
        sdfDate.setTimeZone(TimeZone.getTimeZone("UTC"));
        sdfTime.setTimeZone(TimeZone.getTimeZone("UTC"));
        punchDate = sdfDate.parse(arg1);
        punchTime = sdfTime.parse(arg2);
    }
    catch (ParseException pe)
    {
        System.out.println("Parse exception " +pe.getMessage());
    }

My requirement is basically that i need to make a Date Object from String input but the time zone should remain UTC.


Solution 1:

tl;dr

i need to make a Date Object from String input but the time zone should remain UTC.

LocalDate.parse( 
    "23.01.2017" , 
    DateTimeFormatter.ofPattern( "dd.MM.uuuu" ) 
) 

…and…

LocalTime.parse( "12:34:56" ) 

…combine…

OffsetDateTime.of( datePart , timePart , ZoneOffset.UTC )

Details

You are using troublesome confusing old date-time classes that are now supplanted by the java.time classes.

OffsetDateTime

You say you are certain that your inputs were intended for UTC despite no such indicator. So we will parse the date portion, parse the time-of-day portion, and then combine while assigning an offset-from-UTC of zero for UTC.

DateTimeFormatter f = DateTimeFormatter.ofPattern( "dd.MM.uuuu" ) ;
LocalDate ld = LocalDate.parse( "23.01.2017" , f ) ;

The time-of-day input happens to comply with standard ISO 8601 formatting used by default in the java.time classes. So no need to specify a formatting pattern.

LocalTime lt = LocalTime.parse( "12:34:56" ) ;

Combine.

OffsetDateTime odt = OffsetDateTime.of( ld , lt , ZoneOffset.UTC ) ;

Time zone

If you want to see that same moment as presented in the wall-clock time of a particular region, apply a ZoneId to get a ZonedDateTime.

Specify a proper time zone name in the format of continent/region, such as America/Montreal, Africa/Casablanca, or Pacific/Auckland. Never use the 3-4 letter abbreviation such as EST or IST as they are not true time zones, not standardized, and not even unique(!).

ZoneId z = ZoneId.of( "Europe/Paris" ) ;
ZonedDateTime zdt = odt.atZoneSameInstant( z ) ;  // Same simultaneous moment, same point on the timeline.

ISO 8601

Tip: To exchange this kind of data as text, use the standard ISO 8601 formats exclusively. These formats are sensibly designed to be unambiguous, easy to process by machine, and easy to read across many cultures by people.

The java.time classes use the standard formats by default when parsing and generating strings.

String output = Instant.now().toString() ;  

2017-01-23T12:34:56.123456789Z

Convert

Avoid the legacy java.util.Date class. But if you must, you can convert. Look to new methods added to the old classes.

The Instant class represents a moment on the timeline in UTC with a resolution of nanoseconds (up to nine (9) digits of a decimal fraction).

Extract an Instant object from your OffsetDateTime by calling toString.

Instant instant = odt.toInstant() ;
java.util.Date date = Date.fromInstant( instant ) ;

…going the other way…

Instant instant = myJavaUtilDate.toInstant() ;
OffsetDateTime odt = instant.atOffset( ZoneOffset.UTC ) ;  

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.

Where to obtain the java.time classes?

  • Java SE 8, Java SE 9, and later
    • Built-in.
    • Part of the standard Java API with a bundled implementation.
    • Java 9 adds some minor features and fixes.
  • Java SE 6 and Java SE 7
    • Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
  • Android
    • The ThreeTenABP project adapts ThreeTen-Backport (mentioned above) for Android specifically.
    • See How to use ThreeTenABP….

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.