Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Converting string to date with timezone

I have a string in the pattern yyyy-MM-dd hh:mm a and i can get the time zone object separately in which the above string represents the date.

I want to convert this to the below format. yyyy-MM-dd HH:mm:ss Z

How can i do this?

like image 810
John Avatar asked Nov 17 '10 11:11

John


2 Answers

You can use SimpleDateFormat with yyyy-MM-dd HH:mm:ss and explicitly set the TimeZone:

public static Date getSomeDate(final String str, final TimeZone tz)
    throws ParseException {
  final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm a");
  sdf.setTimeZone(tz);
  return sdf.parse(str);
}

/**
 * @param args
 * @throws IOException
 * @throws InterruptedException
 * @throws ParseException
 */
public static void main(final String[] args) throws ParseException {
  final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z");
  System.out.println(sdf.format(getSomeDate(
      "2010-11-17 01:12 pm", TimeZone.getTimeZone("Europe/Berlin"))));
  System.out.println(sdf.format(getSomeDate(
      "2010-11-17 01:12 pm", TimeZone.getTimeZone("America/Chicago"))));
}

Prints out:

2010-11-17 13:12:00 +0100

2010-11-17 20:12:00 +0100

Update 2010-12-01: If you want to explicitly printout a special TimeZone, set it in the SimpleDateFormat:

sdf.setTimeZone(TimeZone .getTimeZone("IST")); 
System.out.println(sdf.format(getSomeDate(
    "2010-11-17 01:12 pm", TimeZone.getTimeZone("IST"))));

Which prints 2010-11-17 13:12:00 +0530

like image 141
Michael Konietzka Avatar answered Oct 06 '22 09:10

Michael Konietzka


tl;dr

LocalDateTime.parse(                        // Parse string as value without time zone and without offset-from-UTC.
    "2017-01-23 12:34 PM" , 
    DateTimeFormatter.ofPattern( "uuuu-MM-dd hh:mm a" )
)                                           // Returns a `LocalDateTime` object.
.atZone( ZoneId.of( "America/Montreal" ) )  // Assign time zone, to determine a moment. Returns a `ZonedDateTime` object.
.toInstant()                                // Adjusts from zone to UTC.
.toString()                                 // Generate string: 2017-01-23T17:34:00Z
.replace( "T" , " " )                       // Substitute SPACE for 'T' in middle.
.replace( "Z" , " Z" )                      // Insert SPACE before 'Z'.

Avoid legacy date-time classes

The other Answers use the troublesome old date-time classes (Date, Calendar, etc.), now legacy, supplanted by the java.time classes.

LocalDateTime

I have a string in the pattern yyyy-MM-dd hh:mm a

Such an input string lacks any indication of offset-from-UTC or time zone. So we parse as a LocalDateTime.

Define a formatting pattern to match your input with a DateTimeFormatter object.

String input = "2017-01-23 12:34 PM" ;
DateTimeFormatter f = DateTimeFormatter.ofPattern( "uuuu-MM-dd hh:mm a" );
LocalDateTime ldt = LocalDateTime.parse( input , f );

ldt.toString(): 2017-01-23T12:34

Note that a LocalDateTime is not a specific moment, only a vague idea about a range of possible moments. For example, a few minutes after midnight in Paris France is still “yesterday” in Montréal Canada. So without the context of a time zone such as Europe/Paris or America/Montreal, just saying “a few minutes after midnight” has no meaning.

ZoneId

and i can get the time zone object separately in which the above string represents the date.

A time zone is represented by the ZoneId class.

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( "America/Montreal" );

ZonedDateTime

Apply the ZoneId to get a ZonedDateTime which is indeed a point on the timeline, a specific moment in history.

ZonedDateTime zdt = ldt.atZone( z );

zdt.toString(): 2017-01-23T12:34-05:00[America/Montreal]

Instant

I want to convert this to the below format. yyyy-MM-dd HH:mm:ss Z

First, know that a Z literal character is short for Zulu and means UTC. In other words, an offset-from-UTC of zero hours, +00:00.

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).

You can extract a Instant object from a ZonedDateTime.

Instant instant = zdt.toInstant();  // Extracting the same moment but in UTC.

To generate a string in standard ISO 8601 format, such as 2017-01-22T18:21:13.354Z, call toString. The standard format has no spaces, uses a T to separate the year-month-date from the hour-minute-second, and appends the Z canonically for an offset of zero.

String output = instant.toString();

instant.toString(): 2017-01-23T17:34:00Z

I strongly suggest using the standard formats whenever possible. If you insist on using spaces as in your stated desired format, either define your own formatting pattern in a DateTimeFormatter object or just do a string manipulation on the output of Instant::toString.

String output = instant.toString()
                       .replace( "T" , " " )  // Substitute SPACE for T.
                       .replace( "Z" , " Z" ); // Insert SPACE before Z.

output: 2017-01-23 17:34:00 Z

Try this code live at IdeOne.com.


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 and 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 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.

like image 45
Basil Bourque Avatar answered Oct 06 '22 09:10

Basil Bourque