2

I have a set of dates that were saved to the database with the following code (which I can't change):

Date date = new Date()
save(date)

Is there no clean way in groovy to reformat and display the date in the user's local time zone? Such as ...

dateCreated.format('h:mm a MMMM dd, yyyy', Locale.US)

Is nothing like that built into Groovy? Is the only solution?

import java.text.SimpleDateFormat

String date = dateCreated.format('h:mm a MMMM dd, yyyy')
def fmt = new SimpleDateFormat('h:mm a MMMM dd, yyyy', Locale.US);
Date local_time = fmt.parse(date);
String formatted_local = local_time.format('h:mm a MMMM dd, yyyy')
formatted_local

Groovy Date Documentation: http://docs.groovy-lang.org/latest/html/groovy-jdk/java/util/Date.html#format(java.lang.String)

Reference: How to parse month full form string using DateFormat in Java?

Community
  • 1
  • 1
Devon Luongo
  • 127
  • 1
  • 2
  • 11
  • I don't follow your question, but if you think it can be done in Java, then it can also be done in Groovy as that Java snippet is valid Groovy. I'd use `Date.parse('h:mm a MMMM dd, yyyy', '6:31 PM June 27, 2007')` – bdkosher Apr 16 '17 at 02:34
  • Is there a more universal approach? i.e. let's say the date is stored with format 'MM-d-yyyy-h-mm-s' in the database, how do I use Date.parse to print the date in the new format? – Devon Luongo Apr 16 '17 at 05:12
  • You have dates saved as strings in a database? – tim_yates Apr 16 '17 at 07:06
  • For this project they're stored with the Date SQL type (plugged into Grails), but I'm asking generically. First, line of my gross solution turns them into strings because that's what simpleDateFormat takes as input. It's gross which is why the question. – Devon Luongo Apr 16 '17 at 08:24
  • @DevonLuongo, have you got chance to look at the solution provided and try that? – Rao Apr 19 '17 at 01:56
  • @Rao, thanks. That's what I was looking for. – Devon Luongo Apr 19 '17 at 03:21
  • @DevonLuongo, glad that it helped. – Rao Apr 19 '17 at 04:12

2 Answers2

2

Should be pretty simple in Groovy.

Assume, date is saved using below statement

def date = new Date()
println date

Output

Sun Apr 16 11:10:14 UTC 2017

If you need to convert it to specific time zone with specific date time format, just use below statement

println date.format('yyyy/MM/dd HH:mm', TimeZone.getTimeZone('IST'))

Would display output:

2017/04/16 16:40

NOTE: source is in UTC format and converted the existing date to IST format.

In case if you need date object (not string as mentioned in the above), use below:

def date = new Date()
def dtFormat = "yyyy-MM-dd'T'HH:mm:ssZ"
def dt = date.format(dtFormat, TimeZone.getTimeZone('IST'))
assert dt instanceof String

def newDate = Date.parse(dtFormat, dt)
assert newDate instanceof Date

You may quickly try online Demo

Rao
  • 20,781
  • 11
  • 57
  • 77
  • 1
    FYI, the troublesome old date-time classes such as [`java.util.Date`](https://docs.oracle.com/javase/8/docs/api/java/util/Date.html), [`java.util.Calendar`](https://docs.oracle.com/javase/8/docs/api/java/util/Calendar.html), and `java.text.SimpleTextFormat` are now [legacy](https://en.wikipedia.org/wiki/Legacy_system), supplanted by the [java.time](https://docs.oracle.com/javase/8/docs/api/java/time/package-summary.html) classes. – Basil Bourque Apr 16 '17 at 23:32
2

tl;dr

ZonedDateTime.parse ( 
    "Mon Apr 03 16:49:56 PDT 2017" , 
    DateTimeFormatter.ofPattern ( "EEE MMM dd HH:mm:ss z uuuu", Locale.US ) 
) 

Syntax

Sorry, I don’t know Groovy syntax, so this is in Java syntax.

java.util.Date::toString

Are you saying that values were saved to your database as a textual data type by calling java.util.Date::toString?

So now you need to parse the strings in the default format used by java.util.Date::toString such as Mon Apr 03 16:49:56 PDT 2017 to get back to a date-time object.

Firstly, you must already know that was a dreadful way to store a date-time value. That format assumes English, and lops off any fractional second. That format is difficult to read by humans, and difficult to parse by machines. It uses the 3-4 letter abbreviations of pseudo time zones like PDT or IST which are not true time zones, are not standardized, and are not even unique(!). Proper time zone name in the format of continent/region, such as America/Montreal, Africa/Casablanca, or Pacific/Auckland.

ISO 8601

Instead, when serializing date-time values, use standard ISO 8601 formats.

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

Avoid legacy date-time classes

Know that java.util.Date is one of the troublesome poorly-designed confusing old date-time classes bundled with the earliest versions of Java. Those classes are now legacy, supplanted by the java.time classes. Avoid the legacy classes, use java.time instead.

Using java.time

The DateTimeFormatter class parses strings. We must define a formatting pattern to match the output of Date::toString.

String input = "Mon Apr 03 16:49:56 PDT 2017" ;
DateTimeFormatter f = DateTimeFormatter.ofPattern ( "EEE MMM dd HH:mm:ss z uuuu", Locale.US ) ;

Now we can parse that string as a ZonedDateTime.

ZonedDateTime zdt = ZonedDateTime.parse ( input, f ) ;

zdt.toString(): 2017-04-03T16:49:56-07:00[America/Los_Angeles]

Generally the best practice for serializing date-time values for data storage and exchange is to keep the value in UTC and then make a string in standard ISO 8601 format. The convention for UTC in ISO 8601 is to append a Z, short for Zulu and meaning UTC.

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

Instant instant = zdt.toInstant() ;
String output = instant.toString() ;

instant.toString(): 2017-04-03T23:49:56Z

JDBC

Your Question and Comments are not clear. If your values are stored in a database using proper date-time types, then there is no need to mess about with strings as discussed above. If properly stored, you should be letting your JDBC driver do the work of fetching data in and out of the database while converting as necessary.

Drivers compliant with JDBC 4.2 and later can directly use the java.time types via PreparedStatement::setObject and ResultSet::getObject.


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?

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.

Community
  • 1
  • 1
Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
  • I'll try this out next time. Groovy/Grails seems to default to Java.util.Date so I assumed it was standard. Java.time looks much better though. – Devon Luongo Apr 19 '17 at 03:25
  • @DevonLuongo Comparing java.time to the legacy classes is like comparing [Yugo cars](https://en.m.wikipedia.org/wiki/Yugo) to Honda cars – really no comparison at all. – Basil Bourque Apr 19 '17 at 03:33
  • Update: Unfortunately, Grails has compatibility issues with Java.time. A temporary solution has been posted here: http://stackoverflow.com/questions/32974704/grails-3-and-java-8-time-support – Devon Luongo May 07 '17 at 08:28
  • The DateTimeFormatter is not existing. Must be imported: java.time.format.DateTimeFormatter – Nikolai Ehrhardt Jan 24 '22 at 09:51