How to parse a date with timezone correctly? - scala

I'm trying to convert a string of text into a date with the following code:
//Input String
str = "14/01/26,12:13:13+00"
//Format
format = new java.text.SimpleDateFormat("yy/MM/dd,HH:mm:ssz")
//Conversion
format.parse(str)
But I obtain the following:
Exception: Unparseable date: "14/01/26,12:13:13+00"
How does my format have to be changed in order to parse this date correctly?

+00 is invalid time zone. It should be +0000.
You could add 00 to str and replace z with Z in pattern to use RFC 822 time zone format:
new java.text.SimpleDateFormat("yy/MM/dd,HH:mm:ssZ").parse(str + "00")
// java.util.Date = Sun Jan 26 16:13:13 MSK 2014
java.util.Date (and java.text.SimpleDateFormat) is not the best choice for project. See this answer for some details.
As a bonus DateTimeFormat from Joda-Time allows you to parse your str without modifications:
// I'm using the same pattern with `Z` here
DateTimeFormat.forPattern("yy/MM/dd,HH:mm:ssZ").parseDateTime(str)
// org.joda.time.DateTime = 2014-01-26T16:13:13.000+04:00

If you're looking for "correctness", then don't use SimpleDateFormat!
For one thing, it's not thread safe... and it's silently unsafe, you'll just end up with corrupt dates and no error being thrown. As you're using Scala then it's a fair bet that concurrent programming and thread safety will apply to you.
Use JodaTime, perhaps with one of the Scala wrappers. It gives you some far nicer tools for building date parsers, and generally does the right thing if you simply use the default parser without specifying any format string.

Related

GWT compiling java to javascript and time format

in Java I set the date as time in mSec since 1970, e.g. futuredate=1640995200000l //1 Jan 2022.
When this is compiled into JavaScript by GWT, I believe it uses the Jsdate library which says it is a native javascript date object
1 jan 2022 ends up as this object in the JavaScript _.futuredate={l:3120128, m:391243, h:0}
Can someone help me interpret this format please, it doesn't quite make sense to me
thanks
To work with date and time on the GWT client side one can use com.google.gwt.i18n.shared.DateTimeFormat. com.google.gwt.i18n.shared.DateTimeFormat.PredefinedFormat includes already many predefined formats, but you can naturally use your own, such as "EEEE, y MMMM dd".
Based on your example:
Date myDate = DateTimeFormat.getFormat("dd.MM.yyyy").parse("01.01.2022");
DateTimeFormat myFormat = DateTimeFormat.getFormat(PredefinedFormat.ISO_8601);
String s = myFormat.format(myDate);
The first line only simulates the date that you already set in Java and it is meant to show another example of a date format and how to parse a String.

Could not find the format for this date: "2018-09-09T09:04:47+00:00"

Getting Error
java.text.ParseException: Unparseable date: "2018-09-09T09:04:47+00:00"
Whatis the date format is this?
There seems to be some confusion, about this date format, so I will explain.
This is an ISO 8601 date-time value with a timezone offset.
References:
The ISO 8601 page in Wikipedia is accurate and pretty comprehensive.
The W3 Consortium have documented in a TR; here.
The Official version may be obtained from ISO; here.
The Z is an ISO standard timezone specifier. It means the same thing as +00.00, and is known in some circles (e.g. the military) as "Zulu time".
An ISO 8601 date/time does not "have to" end with a Z. There are other forms of timezone specification, and indeed a date/time does not need a timezone at all.
You should not need to trim it off the Z. Java's data-time parsers can parse the Z timezone specifier and give it its correct meaning ... if you use the right pattern.
If an ISO date time is "unparseable", that means that you have (explicitly or implicitly) used the wrong format to parse it.
Unfortunately, different countries (locales) have different default date / time formats, and worse still there is no reliable way (in general) to know which is the correct one to use ... if you don't know where it came from.
Fortunately ... ISO 8601 is an international standard. If you see a date / time that conforms to the ISO 8601 syntax, you know what it means.
There are a number of kinds of ISO 8601 date and date/time representation as explained in the W3 Consortium TR. The different kinds can be distinguished without any ambiguity.
If you are parsing using java.text.SimpleDateFormat, then the correct pattern for this variation of ISO 8601 is "yyyy-MM-dd'T'HH:mm:ssX". The pattern that works with java.time.format.DateTimeFormatter is also "yyyy-MM-dd'T'HH:mm:ssX"
The DateTimeFormatter class also defines a number of standard formats as constants. The format for this kind of ISO 8601 date/time is DateTimeFormatter.ISO_OFFSET_DATE_TIME. The other kinds are defined too.
The Date and Calendar classes and associated classes are legacy classes. It is advisable to use the new java.time classes instead in new code.
You should use 'X' for timezone:
String pattern = "yyyy-MM-dd'T'HH:mm:ssX";
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern);
Date date = simpleDateFormat.parse("2018-09-09T09:04:47+00:00");
System.out.println(date);
Use this convert method to String to date which is ISO format. But in generaly ISO format ends with Z , but if not no problem. This method returns Date, and do it what ever u want from this return value.
public static Date toCalendar( String isoDate)
throws ParseException {
String s = isoDate.replace("Z", "+00:00");
try {
s = s.substring(0, 22) + s.substring(23); // to get rid of the ":"
} catch (IndexOutOfBoundsException e) {
throw new ParseException("Invalid length", 0);
}
return new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ").parse(s);
}
In Java8 TimeApi or later version has this usage,try it ;
OffsetDateTime offsetDateTime = OffsetDateTime.parse( "2018-09-09T09:04:47+01:00" );
Instant instant = offsetDateTime.toInstant();
java.util.Date date = java.util.Date.from( instant );
Or use only this pattern yyyy-MM-dd'T'HH:mm:ssX

How to convert local date to UTC in Mirth?

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!
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!
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?
Java SE 8, Java SE 9, Java SE 10, 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
Later versions of Android bundle implementations of the java.time classes.
For earlier Android (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). 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.
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 :)
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));
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

Scala Joda Time Format Malformed

I can't find many Scala examples with Joda time especially with formatting but here is the error:
Exception in thread "main" java.lang.IllegalArgumentException: Invalid format: "2015-12-11T13:35:45.732-05:00" is malformed at "15-12-11T13:35:45.732-05:00"
Here is the code:
val now = DateTime.now.toString()
val dtf = DateTimeFormat.forPattern("MM-dd-yyyy HH:mm:ss");
val timeForm = dtf.parseDateTime(now)
Most of the java exmaples all seem to work fine with this?
It has nothing to do with Scala. MM-dd-yyyy HH:mm:ss means the string will start with month, then day, etc. (see http://joda-time.sourceforge.net/apidocs/org/joda/time/format/DateTimeFormat.html for the meaning of characters in the patterns). 2015-12-11T13:35:45.732-05:00 obviously doesn't. Either use val now = dtf.printDateTime(DateTime.now) to print current datetime in the same format you are planning to parse, or use the correct format to parse it.

Joda-time parser with instance-local default timezone

Is there an "instance-local" version of Joda's DateTimeZone.setDefault? I'm trying to achieve something like this:
val parser = new ParserWithDefaultTimezone("GMT+1");
parser.parse("1970-01-01 00:00:00").getMillis // -3600000L
parser.parse("1970-01-01 00:00:00 UTC").getMillis // 0L
Without polluting anything global. All I can find in the Joda docs is something that (ironically) modifies global state.
If there is a non-Joda solution, I am interested in that, too.
EDIT: Forgot to mention that if there is no ready-to-use class that does this, I'll settle for: "what is the easiest way to see if a time string contains an explicit timezone?" I can't distinguish between an explicit one and a timezone that Joda set by default.
EDIT 2: I don't have a format string to feed; I'm looking for something that infers the format at runtime.
You can use withZone to alter the date/time zone used:
val fmt = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss ZZZ").withZone(DateTimeZone.forID("Europe/Berlin"))
val date = fmt.parseDateTime(???);
The set-up required to make the time zone optional is a little bit more complicated:
val tz = new DateTimeFormatterBuilder().appendLiteral(" ").appendTimeZoneId().toFormatter()
val fmt = new DateTimeFormatterBuilder()
.append(DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss"))
.appendOptional(tz.getParser())
.toFormatter().withZone(DateTimeZone.forID("Europe/Berlin"))
println(fmt.parseDateTime("1970-01-01 12:00:00 UTC"))
println(fmt.parseDateTime("1970-01-01 12:00:00 Europe/Berlin"))
println(fmt.parseDateTime("1970-01-01 12:00:00"))
As long as your remark
I don't have a format string to feed; I'm looking for something that infers the format at runtime.
applies only with respect to the time zone, solution 2 might do what you want. If, on the other hand, you really don't know, in wich format the dates are provided (dd/mm/yyyy vs. mm/dd/yyyy vs. yyyy/mm/dd vs. whatever), then I think you are out of luck: such a conversion would be ambiguous at best. Is 01/03/2015 the 1st of March or the 3rd of January?