Problem:
I should parse an RFC3339 date string. It works fine with ISO_ZONED_DATE_TIME:
ZonedDateTime.parse("1985-04-12T23:20:50.52Z", ISO_ZONED_DATE_TIME);
ZonedDateTime.parse("1996-12-19T16:39:57-08:00", ISO_ZONED_DATE_TIME);
Let's say I'll fix a problem of Unknown Local Offset Convention just to not accept these dates.
But I still have a problem with some corner cases like this:
1990-12-31T23:59:60Z
This represents the leap second inserted at the end of 1990.
1990-12-31T15:59:60-08:00
This represents the same leap second in Pacific Standard Time, 8
hours behind UTC."1990-12-31T15:59:60-08:00"
Question:
How can I parse it avoiding to lose any seconds?
Update:
Does it exist any alternative to ZonedDateTime that suits well
RFC3339?
java.time doesn’t offer any direct support for what you want. Just earlier today I wrote this answer that also has a section on parsing a leap second. But what is said there is all there is.
So there’s hand parsing left. I’d try something along these lines: Use a regular expression for detecting whether the second is 60. If so: Substitute it with 59. Parse. Convert to UTC. If the time of day in UTC is 23:59:59, assume there was a valid leap second in the original string; otherwise the string didn’t denote a valid time.
I suggest that in case of a leap second second values up to 60.999999999 are valid. So to detect whether there is a 60 you need to look at what comes after the colon (if any) after the minutes, and not depend on whether there is a fractional part too.
Related
I have a question. I've never did that before. So how I can to convert time in format, what Google Places Api is giving me, and to get hour of day from that?
From the Google Places API documentation:
periods[] is an array of opening periods covering seven days, starting from Sunday, in chronological order.
Each period contains:
open contains a pair of day and time objects describing when the place opens:
day a number from 0–6, corresponding to the days of the week, starting on Sunday. For example, 2 means Tuesday.
time may contain a time of day in 24-hour hhmm format (values are in the range 0000–2359). The time will be reported in the place’s timezone.
close may contain a pair of day and time objects describing when the place closes. Note: If a place is always open, the close section will be missing from the response. Applications can rely on always-open being represented as an open period containing day with value 0 and time with value 0000, and no close.
Based on this, it's up to you to parse the information and format it appropriately.
Why are you trying to parse out JSON? If you're using Java, stick to Java. You have access to the actual objects. What's the point in using the client services API?
PlaceDetails place = PlacesApi.placeDetails(new GeoApiContext.Builder().apiKey(API_KEY).build(), "insert place id");
for (Period period : place.openingHours.periods)
{
LocalTime time = period.open.time;
}
I have 2 different computers, each with different TimeZone.
In one computer im printing System.currentTimeMillis(), and then prints the following command in both computers:
System.out.println(new Date(123456)); --> 123456 stands for the number came in the currentTimeMillis in computer #1.
The second print (though typed hardcoded) result in different prints, in both computers.
why is that?
How about some pedantic detail.
java.util.Date is timezone-independent. Says so right in the javadoc.
You want something with respect to a particular timezone? That's java.util.Calendar.
The tricky part? When you print this stuff (with java.text.DateFormat or a subclass), that involves a Calendar (which involves a timezone). See DateFormat.setTimeZone().
It sure looks (haven't checked the implementation) like java.util.Date.toString() goes through a DateFormat. So even our (mostly) timezone-independent class gets messed up w/ timezones.
Want to get that timezone stuff out of our pure zoneless Date objects? There's Date.toGMTString(). Or you can create your own SimpleDateFormatter and use setTimeZone() to control which zone is used yourself.
why is that?
Because something like "Oct 4th 2009, 14:20" is meaningless without knowing the timezone it refers to - which you can most likely see right now, because that's my time as I write this, and it probably differs by several hours from your time even though it's the same moment in time.
Computer timestamps are usually measured in UTC (basically the timezone of Greenwich, England), and the time zone has to be taken into account when formatting them into something human readable.
Because that milliseconds number is the number of milliseconds past 1/1/1970 UTC. If you then translate to a different timezone, the rendered time will be different.
e.g. 123456 may correspond to midday at Greenwich (UTC). But that will be a different time in New York.
To confirm this, use SimpleDateFormat with a time zone output, and/or change the timezone on the second computer to match the first.
javadoc explains this well,
System.currentTimeMillis()
Note that while the unit of time of the return value is a millisecond, the granularity of the value depends on the underlying operating system and may be larger. For example, many operating systems measure time in units of tens of milliseconds.
See https://docs.oracle.com/javase/7/docs/api/java/util/Date.html#toString().
Yes, it's using timezones. It should also print them out (the three characters before the year).
Is there any function or library which gets a date in milliseconds, given a String?
This question shows how to convert a formatted String to a Date object, but is there any way to do this with an unformatted String?
Basically, the task is impossible. Here's an example:
01/04/2012
In the US, that means January 4th 2012. In Australia, that mean 1st April 2012.
Without knowing where you are and what date formats conventionally mean, it is impossible to accurately map an arbitrary date-like string to a date time value that matches what the user actually meant.
And even if you do know about the relevant local conventions, users have a remarkable propensity to be oblivious to ambiguity. Dealing with that may require deep domain knowledge (or mind reading skills!) to disambiguate the possible meanings.
When you think about it, this is why modern user interfaces typically use a date-picker widget of some kind when the user needs to enter a date / time
first convert the string to Date. From there you can get time in milis using Date.getTime() method
Is there a way to force Joda time to parse dates only when they contain four digit years? For example:
2009-11-11 - should parse
09-11-11 - should not parse
Tried the following code:
DateTimeFormatterBuilder builder = new DateTimeFormatterBuilder();
DateTimeFormatter formatter = builder.appendYear(4, 4).appendLiteral('-').appendMonthOfYear(1).appendLiteral('-').appendDayOfMonth(1).toFormatter();
formatter.parseDateTime("09-11-11");
Parses into 0009-11-11. Apparently minDigits in the method appendYear are only used for formatting when printing out the date.
The result is the same if I use appendYearOfEra(). If I use appendYearOfCentury(), it parses the year into 1909 instead.
We are implementing a general data parser, which will recognize various types of inputs. Also the example is a shortened form of the real deal (for simplicity). Real life scenarios parses dates which can have weekdays, months as words, time, zone and different characters separating month, day and year. Therefore, writing a RegEx or checking the content/length of the string can prove rather difficult.
Some real examples could look like this:
2009-11-11
Wednesday 2009-11-11T15:00:00
2009/11/11 15:00
and many more...
DateTimeFormatterBuilder#appendFixedDecimal() may well do what you need.
Alternatively, you could implement the DateTimeParser interface to create whatever parser you want and pass that into the DateTimeFormatterBuilder.
You can check the length of the date string.
You can build extremely specific parsers and formatters using DateTimeFormatterBuilder. There's generally no need to use this class directly, since most common formats are more easily available elsewhere in the API, but this is the builder class they all use under the covers.
What do you want to get from a user who enters '0001-01-01' as the date (that is, they entered 4 digits for the year, but the first three were zeroes)? What about '0999-12-31'? And '999-12-31'? And what about '10000-01-01' - the infamous Y10K1 problem?
If that is a legitimate value, then you are stuck with discovering the length of what the user typed as the year portion of the date (probably after any other parsing has been done), and making sure it is at least (or is it exactly?) four digits.
If that is not a legitimate value, then you are stuck with checking the year value after the date is parsed.
Or you can take the code and modify it so it includes your preferred definition of valid year.
1 I do not plan to start working on fixing the Y10K problem before 5000-01-02.
I have seen way to many places where a method takes a long or an int to represent durations in either nanoseconds, milliseconds (most common), seconds and even days. This is a good place to look for errors, too.
The problem is also quite complex once you realize that you can mean for the duration to be a certain number of seconds, or an interval that fits the human perception of time better, so that a duration of 24 hours is always going to be the next day at the same "wall-clock" time. Or that a year is either 365 or 366 days depending on the date, so that a year from 28th of February is always going to be the 28th of February.
Why is there no distinct type to represent this? I have found none in either Java or .net
In .Net you can use the TimeSpan structure to represent a length of time.
For Java, take a look at Joda (an intuitive and consistent date/time library) and its Duration and Period classes. DateTime objects can handle addition and manipulation via these objects.
(answer changed to reflect the comments below re. the Period class)
It's not an easy problem. Maybe Joda-Time would be a useful library for you. It has a Duration class that can do what you are asking for.