4

In Mirth I receive a local datetime string (201801011000) which I need to convert to UTC. I soon found out using the classic js new Date() doesn't work well.

This for example:

var d = new Date("2018-01-01 10:00");
logger.info(d.toString());

gives me an Invalid Date.

So after some more searching I found I can do this:

var d = DateUtil.getDate("yyyyMMddHHmm", "201801011000");

and from here I'm stuck. I don't know how I can convert this to UTC. Local server timezone is assumed which is enough for now, but in the future I also need to set a specific non-local timezone.

I tried to get the methods I can use with Object.getOwnPropertyNames(d), but that gives me the helpfull TypeError: Expected argument of type object, but instead had type object

I also tried looking up the java docs for DateUtil and tried some methods from that, but nothing worked.

Does anybody know how I can convert datestring from local time to UTC? All tips are welcome!

kramer65
  • 50,427
  • 120
  • 308
  • 488
  • According to [these docs](http://javadocs.mirthcorp.com/connect/3.1.0/user-api/com/mirth/connect/server/userutil/DateUtil.html), it looks like this is Java and it returns a `java.util.Date` object? If so, that question has been answered many times already. I'm a bit confused because I don't know Mirth and you mentioned "classic js" - so is this Java or JavaScript? – Matt Johnson-Pint Jun 12 '18 at 23:30
  • 1
    I can not answer the question, but as a background - it's kind of both. :) Mirth uses Rhino JavaScript engine for it's scripting, which means you write JS code and have access to all Java classes in the classpath. It can and does get confusing with issues like "is it a JavaScript or Java String object I'm handling here?!". I can only assume, that it's similar with date and time manipulations. – Tarmo R Jun 13 '18 at 15:59
  • 1
    @TarmoR That sounds hellish – bert Jul 23 '18 at 15:49
  • FYI, the terribly troublesome old date-time classes such as [`java.util.Date`](https://docs.oracle.com/javase/10/docs/api/java/util/Date.html), [`java.util.Calendar`](https://docs.oracle.com/javase/10/docs/api/java/util/Calendar.html), and `java.text.SimpleDateFormat` are now [legacy](https://en.wikipedia.org/wiki/Legacy_system), supplanted by the [*java.time*](https://docs.oracle.com/javase/10/docs/api/java/time/package-summary.html) classes built into Java 8 and later. See [*Tutorial* by Oracle](https://docs.oracle.com/javase/tutorial/datetime/TOC.html). – Basil Bourque Jul 23 '18 at 18:24
  • You should use the latest java classes given from java8 for conversion.I have added my answer for your explanation. – NullPointer Jul 24 '18 at 01:20

5 Answers5

4

Ok, after messing around with this for about two full days I finally found a solution. In the end I had to tap into Java, but since I couldn't import any java dependencies I had to use their direct class path (e.g.: java.text.SimpleDateFormat).

In the end this is what worked for me:

var datestr = "201207011000".slice(0, 12);  // This is just a datetime string to test with

var formatter_hl7 = new java.text.SimpleDateFormat("yyyyMMddHHmm");
formatter_hl7.setTimeZone(java.util.TimeZone.getTimeZone("CET"));
var formatter_utc = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm");
formatter_utc.setTimeZone(java.util.TimeZone.getTimeZone("UTC"));

var date_in_utc = formatter_utc.format(formatter_hl7.parse(date_str));

Regardless, I wish you all a beautiful day!

kramer65
  • 50,427
  • 120
  • 308
  • 488
1

tl;dr

  • Do not use DateUtil whatever that is. (Perhaps Apache DateUtils library?)
  • Do not use terrible old date-time classes such as java.util.Date.
  • Use the modern industry-leading java.time classes.

Code for parsing a string lacking an offset, then assigning an offset of zero for UTC itself.

LocalDateTime                // Represents a date and a time-of-day but without any concept of time zone or offset-from-UTC. NOT a moment, NOT a point on the timeline.
.parse( 
    "201801011000" ,
     DateTimeFormatter.ofPattern( "uuuuMMddHHmm" )
)  
.atOffset( ZoneOffset.UTC )  // Assign an offset-from-UTC. Do this only if you are CERTAIN this offset was originally intended for this input but was unfortunately omitted from the text. Returns an `OffsetDateTime`.
.toInstant()                 // Extract an `Instant` from the `OffsetDateTime`. Basically the same thing. But `Instant` is always in UTC by definition, so this type is more appropriate if your intention is to work only in UTC. On the other hand, `Instant` is a basic class, and `OffsetDateTime` is more flexible such as various formatting patterns when generating `String` object to represent its value.

Using java.time

The modern approach in Java uses the java.time classes. This industry-leading framework supplanted the terribly troublesome old date-time classes such as Date, Calendar, and SimpleDateFormat.

DateTimeFormatter

Parse your input string. Define a formatting pattern to match.

DateTimeFormatter f = DateTimeFormatter.ofPattern( "uuuuMMddHHmm" ) ;
String input = "201801011000" ;

LocalDateTime

Parse as a LocalDateTime because your input lacks an indicator for time zone or offset-from-UTC.

LocalDateTime ldt = LocalDateTime.parse( input , f ) ;

Lacking a zone or offset means this does not represent a moment, is not a point on the timeline. Instead, this represents potential moments along a range of about 26-27 hours, the range of time zones around the globe.

OffsetDateTime

If you know for certain that this date and time-of-day were intended to represent a moment in UTC, apply the constant ZoneOffset.UTC to get an OffsetDateTime object.

OffsetDateTime odt = ldt.atOffset( ZoneOffset.UTC ) ;

ZonedDateTime

Your Question is vague. It sounds like you might know of an specific time zone intended for this input. If so, assign a ZoneId to get a ZonedDateTime object.

Understand that an offset-from-UTC is but a mere number of hours, minutes, and seconds. Nothing more, nothing less. In contrast, a time zone is much more. A time zone is a history of past, present, and future changes to the offset used by the people of a certain region.

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( "Africa/Tunis" ) ;
ZonedDateTime zdt = ldt.atZone( z ) ;

Instant

A quick way to adjust back into UTC is to extract a Instant object. An Instant is always in UTC.

Instant instan = zdt.toInstant() ;

ISO 8601

Tip: Instead of using custom format for exchanging date-time values as text, use only the standard ISO 8601 formats. The standard formats are practical, easy to parse by machine, easy to read by humans across cultures.

The java.time classes use the ISO 8601 formats by default when parsing/generating strings. The ZonedDateTime::toString method wisely extends the standard to append the name of the zone in square brackets.

Instant instant = Instant.parse( "2018-07-23T16:18:54Z" ) ;  // `Z` on the end means UTC, pronounced “Zulu”. 
String output = instant.toString() ;  // 2018-07-23T16:18:54Z

And always include the offset and time zone in your string. Omitting the offset/zone for a moment is like omitting the currency for a price: All you have left is an ambiguous number worth nothing. Actually, worse than nothing as it can cause all sorts of confusion and errors.


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
  • [DateUtil](http://javadocs.mirthcorp.com/connect/3.0.0/user-api/com/mirth/connect/server/userutil/DateUtil.html) belongs to mirth's flavor of java. Its name couldn't be more spot on: a date utility class lacking in utility. – Mr.Z Apr 02 '21 at 00:39
0

In my project have function for convert datestring local time to UTC,

function getDateInUTC(dateString) {
    return new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm").setTimeZone(java.util.TimeZone.getTimeZone("UTC")).format(new java.text.SimpleDateFormat("yyyyMMddHHmm").setTimeZone(java.util.TimeZone.getTimeZone("CET")).parse(dateString));
}

Enjoy :)

Yogesh Rathi
  • 6,331
  • 4
  • 51
  • 81
0

You should use the latest classes java.time provided from Java8.

Steps are as follows:

Step-1. Parse String to LocalDateTime

Step-2. Convert LocalDateTime to the ZonedDateTime and then we can convert between different timezone.

Hope this help:

In Mirth you can write as:

String str = "201207011000"; 
var date_in_utc =java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")
                .format(java.time.ZonedDateTime.of(java.time.LocalDateTime
                .parse(str,java.time.format.DateTimeFormatter
                .ofPattern("yyyyMMddHHmm")),java.time.ZoneId.of("CET"))
                .withZoneSameInstant(java.time.ZoneOffset.UTC));

Full Snippet:

ZoneId cet = ZoneId.of("CET");
String str = "201207011000";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMddHHmm");
LocalDateTime localtDateAndTime = LocalDateTime.parse(str, formatter);
ZonedDateTime dateAndTimeInCET = ZonedDateTime.of(localtDateAndTime, cet );
System.out.println("Current date and time in a CET timezone : " + dateAndTimeInCET);
ZonedDateTime utcDate = dateAndTimeInCET.withZoneSameInstant(ZoneOffset.UTC);
System.out.println("Current date and time in UTC : " + utcDate);
System.out.println("Current date and time in UTC : " + DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm").format(utcDate));
NullPointer
  • 7,094
  • 5
  • 27
  • 41
-2

Give this a shout

var d = DateUtil.getDate("yyyyMMddHHmm", "201801011000");
var utcD = new Date(d).toISOString();

edit: Info on .toISOString() https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString

Boosh
  • 1
  • 1
  • Hey Boosh. Sorry for the late reply. I tried your suggestion, but unfortunately just get `RangeError: Date is invalid.` for the second line. I logged `d`, and that is an object correctly pointing to the first of jan 2018 at 10 o' clock. No idea why `Date` cannot be used. Any other ideas? – kramer65 Jul 17 '18 at 09:09