Joda-time parser with instance-local default timezone - scala

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?

Related

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

Format date and add month to it

I'm currently working with embarcadero c++, this is the first time I'm working with it so it's completely new to me.
What I'm trying to achieve is to get the current date, make sure the date has the "dd/MM/yyyy" format. When I'm sure this is the case I want to add a month to the current date.
So let's say the current date is 08/18/2016 this has to be changed to 18/08/2016 and then the end result should be 18/09/2016.
I've found that there is a method for this in embarcardero however I'm not sure how to use this.
currently I've only been able to get the current date like this.
TDateTime currentDate = Date();
I hope someone will be able to help me out here.
I figured it out.
After I've searched some more I found the way to use the IncMonth method on this page.
The example given my problem is as follows:
void __fastcall TForm1::edtMonthsExit(TObject *Sender)
{
TDateTime StartDate = edtStartDate->Text;
int Months = edtMonths->Text.ToInt();
TDateTime NextPeriod = IncMonth(StartDate, Months);
edtNextPeriod->Text = NextPeriod;
}
After looking at I changed my code accordingly to this
TDateTime CurrentDate = Date();
TDateTime EndDate = IncMonth(CurrentDate, 1);
A date object doesn't have a format like "dd/MM/yyyy". A date object is internally simply represented as a number (or possibly some other form of representation that really isn't your problem or responsibility).
So you don't have to check if it's in this format because no date objects will ever be in this format, they simply don't have a format.
You will have to do additions/subtractions on the Date object that the language or library gives you, THEN (optionally) you can format it to a human-readable string so it looks like 18/08/2016 or 18th of August 2016 or whatever other readable format that you choose.
It might be that the TRANSFER of a date between 2 systems is in a similar format, but then formatting the date like that is entirely up to you.
As for how to do that, the link you posted seems like a possible way (or alternatively http://docwiki.embarcadero.com/Libraries/Berlin/en/System.SysUtils.IncMonth), I'm afraid I can't give you an example as I'm not familiar with the tool/language involved, I'm just speaking generically about Date manipulations and they should ALWAYS be on the raw object.

joda time ISO DateTime formatting

I'm using joda time to format my ISO Date input string, but I'm getting an exception that my ISO Date is malformed:
Invalid format: "2014-06-20T11:41:08+02:00" is malformed at "+02:00"
This is my code:
val formatter: DateTimeFormatter = ISODateTimeFormat.dateTime.withZone(DateTimeZone.getDefault)
val date: DateTime = formatter.parseDateTime("2014-06-20T11:41:08+02:00")
What's wrong here?
The error comment is slightly misleading here, as Joda formatter you derive from ISODateTimeFormat expects the millisecond part of the date/time string to be present, therefore the following will work fine:
val formatter: DateTimeFormatter = ISODateTimeFormat.dateTime().withZone(DateTimeZone.getDefault())
val date: DateTime = formatter.parseDateTime("2014-06-20T11:41:08.0+02:00")
The answer by Radyk is correct.
ISO 8601 Formats Built-In
However, you needn't specify a formatter at all. The DateTime class has a built-in parser for your ISO 8601 compliant format, used automatically by the constructor.
DateTime dateTime = new DateTime( "2014-06-20T11:41:08+02:00", timeZone );
While the second argument is optional, I suggest you assign a DateTimeZone object to be assigned to the DateTime if you know such a time zone. The input string has an offset-from-UTC, but a time zone is more than just an offset. A time zone includes rules for Daylight Saving Time and other anomalies. Use proper time zone names, never 3 or 4 letter codes like EST or IST.
Other Formats
You can apply many other formats:
Built-in ISO 8601 formatters
Built-in localized (short, medium, long, and full formats, Locale-sensitive)
Custom specified by you.
For example, if you want only the date portion without the time-of-day in your String representation, call ISODateTimeFormat.date() to access a built-in formatter.
Example code in Joda-Time 2.8.
String output = ISODateTimeFormat.date().print( dateTime ); // Format: yyyy-MM-dd
Search StackOverflow for hundreds of other Questions and Answers about formatting date-time values.

How to parse a date with timezone correctly?

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.

Why do I need to parse dates in Grails?

I am in the unfortunate position that I need to use a composite id in a Grails app where I work with legacy data. This means I have to override some actions in the controller, but as I did this I was struck by the fact that I could not use use a date argument directly as a parameter to a dynamic method.
Instead of just doing MyLegacyObj.findBySystemIdAndLogDate(params.systemId, params.logDate), I first needed to parse the date string before giving it to the dynamic method. To further complicate matters I had no idea what format the date string had (until I added lots of log.debug() string to the output). So now I have a bit of code looking like this
def formatter = new SimpleDateFormat("EEE MMM d HH:mm:ss z yyyy")
MyLegacyObj.findBySystemIdAndLogDate(params.systemId, formatter.parse(params.logDate));
This feels unoptimal, no to say dangerous (what if the date format changes with the locale?)? What would be a recommended way of doing this, and do I really need to parse dates at all?
Date is a pretty complex object and params are just Strings, so Date is submitted in parts. It is "magically" assembled from the parts when assigning x.properties = params.
Command object will do the work for you, if you add a Date field to it.
It has nothing to do with methods' dynamic or static invocation. Your GSP that renders Date editor might interfere too.