ISO 8601 date-time format combining 'Z' and offset of '+0000' - time

I'm playing with date-time format from ISO 8601. I have this pattern:
"yyyy-MM-dd'T'HH:mm:ssZZ'Z'"
and the output is:
"2015-11-17T00:00:00+0000Z"
My question is if the output is ok, if is possible to have in a date +0000 and Z taking in account both has the same meaning time zone offset/id. Thanks in advance for clarification =)

No, not OK
No, the Z is an offset-from-UTC so it should not be combined redundantly with a numerical offset of +00:00 or +0000.
ISO 8601
While I do not have access to a paid copy of the ISO 8601 spec, the Wikipedia page clearly states that the Z must follow the time-of-day:
…add a Z directly after the time without a space.
IETF RFC 3339
The freely-available RFC 3339, a profile of ISO 8601, defines a Z as being attached to a time-of-day:
A suffix … applied to a time …
The RFC also states with formal ABNF notation that we should use either a Z or a number. In ABNF, the slash (SOLIDUS) means “or” (exclusive ‘or’), while the pair of square brackets means “optional”.
time-numoffset = ("+" / "-") time-hour [[":"] time-minute]
time-zone = "Z" / time-numoffset
Furthermore, section 5.4 of the spec specifically recommends against including redundant information.
Java
The modern java.time classes built into Java use the standard ISO 8601 formats by default when parsing/generating strings. See Oracle Tutorial.
Parsing text input
With Z:
Instant instant = Instant.parse( "2019-01-23T12:34:56.123456789Z" ) ;
With +00:00:
OffsetDateTime odt = OffsetDateTime.parse( "2019-01-23T12:34:56.123456789+00:00" ) ;
Generating text output
To create a string with the Z, simply call Instant::toString.
String output = Instant.now().toString() ; // Capture the current moment in UTC, then generate text representing that value in standard ISO 8601 using the `Z` offset-indicator.
2019-05-22T21:00:52.214709Z
To create a string with the 00:00, call OffsetDateTime::format. Generate text using a DateTimeFormatter with a formatting pattern you define.
DateTimeFormatter f = DateTimeFormatter.ofPattern( "uuuu-MM-dd'T'HH:mm:ss.SSSxxx" ) ;
String output = OffsetDateTime.now( ZoneOffset.UTC ).format( f ) ;
2019-05-22T21:00:52.319076+00:00
Truncating
You may want to truncate any microseconds or nanoseconds.
Instant
.now()
.truncatedTo( ChronoUnit.MILLIS )
.toString()
2019-05-22T21:11:28.970Z
…and…
OffsetDateTime
.now( ZoneOffset.UTC )
.truncatedTo( ChronoUnit.MILLIS )
.format(
DateTimeFormatter.ofPattern( "uuuu-MM-dd'T'HH:mm:ss.SSSxxx" )
)
2019-05-22T21:11:29.078+00:00
See this code running live at IdeOne.com.

Related

lazarus/pascal write filename with current date

i need to write a file with the filename containing the current date.. everything works besides the date, it gives a class exception 'run error(3)'
(the importo.text is the text of a TEdit.. but i guess it's irrelevant)
uses
Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls;
...
var
contributo:real;
f:textfile;
...
datee: string;
...
contributo:= (StrToInt(importo.text)/ 100)*4;
datee:= DateToStr(Date);
assignfile(f,'fattura minimi n.'+n.text+' '+datee+'.txt');
rewrite(f);
writeln(f,'Giovanna Migliore');
...
closefile(f);
DateToStr() will return the date formatted according to regional settings. In your case this is almost certainly returning a folder/path delimiter character (/ or \) which is causing the problem (path not found).
Even if you change your regional settings to avoid using such characters, the code will still fail on other systems if those regional settings are not "compatible". To avoid this you need to ensure that your encoding of the date in the filename is not sensitive to such potential problems.
You could remove/replace any such characters after forming the filename, or you could explicitly encode the date in a manner that will not introduce such characters to start with, similar to:
var
y, m, d: Word;
..
DecodeDate(Date, y, m, d);
dateStr := Format('%4d-%2d-%2d', [y, m, d]);
// e.g. dateStr value for 31st Dec 2016 would be: '2016-12-31'
You could then incorporate the date component values in your filename either by concatenation as required, or directly in a single format statement:
filename := Format('fattura minimi n.%s %4d-%2d-%2d.txt [n.text, y, m, d]);
assignfile(f, filename);

How do I parse an ISO 8601 Timestamp in Go?

I know I need to use a time layout in Go (as shown here https://golang.org/src/time/format.go) but I can't find the layout for an ISO 8601 timestamp.
If it helps, I get the timestamp from the Facebook API. Here is an example timestamp: 2016-07-25T02:22:33+0000
I found this layout to work: "2006-01-02T15:04:05-0700"
The problem here is that RFC3339 requires the zone offset to be given as "+00:00" (or "Z" in case of UTC) while ISO8601 allows it to be "+0000".
From RFC3339:
[...]
time-numoffset = ("+" / "-") time-hour ":" time-minute
time-offset = "Z" / time-numoffset
[...]
full-time = partial-time time-offset
date-time = full-date "T" full-time
So instead of the time.RFC3339 layout
"2006-01-02T15:04:05Z07:00"
you have to use:
"2006-01-02T15:04:05Z0700"
RFC3339 is equivalent to ISO 8601. Specifically, it has identical format, RFC3339 just has stricter requirements (example, it requires a complete date representation with 4-digit year).
What's the difference between ISO 8601 and RFC 3339 Date Formats?
So you can use the constant time.RFC3339 as your layout.
You have that to use the some layout of your date.
data := "2022-01-24T00:00:00.000-03:00"
layout := "2006-01-02T15:04:05.000-03:00"
dataTime, err := time.Parse(layout, data)

What kind of date format is this and how do I transform it?

Making a GET request to a private (no public documentation) API returns data in JSON format.
The value for date looks as follows:
AanmeldDatum: "/Date(1262300400000+0100)/"
There's another variable called AangebodenSindsTekst which means OfferedSinceText and it's value is "8 augustus 2014". So the unknown Date format should get parsed into that specific value.
I'm wondering what kind of date format it is and how can I transform this to something like this 2014-08-08 with Ruby?
I've tried this:
require 'time'
t = '1262300400000+0100'
t2 = Time.parse(t)
# => ArgumentError: no time information in "1262300400000+0100"
Ruby's Time class is your friend, especially the strptime method:
require 'time'
foo = Time.strptime('1262300400000+0100', '%N') # => 2014-08-08 16:57:25 -0700
foo = Time.strptime('1262300400000+0100', '%N%z') # => 2014-08-08 08:57:25 -0700
%N tells Ruby to use nanoseconds. It's throwing away the precision after the 9th digit which is OK if you don't need the rest of the value. Nanosecond accuracy is good enough for most of us.
%z tells Ruby to find the timezone offset, which it then applies to the returned value.
While parse can often figure out how to tear apart an incoming string, it's not bullet-proof, nor is it all-knowing. For speed, I'd recommend learning and relying on strptime if your strings are consistent.
As the Tin Man pointed out in this answer, use the following instead:
Time.strptime('1262300400000+0100', '%Q%z')
it could be milliseconds since epoc, take off the last 3 zeros and plug it into a unix time stamp converter, comes out as Dec 31st 2009
TIME STAMP: 1262300400
DATE (M/D/Y # h:m:s): 12 / 31 / 09 # 11:00:00pm UTC

Ruby local_to_utc returns invalid year

I have the following date string ('US/Eastern'), which I need to convert to UTC:
date_src = '2014-07-07T23:10:00+0'
First I convert it to a "valid" format so I can operate it on later processes. I use the following to have an iso version of the date:
date = DateTime.parse(date_src).iso8601
At this point date is a nice '2014-07-07T23:10:00+00:00'. The last step on my process is to translate this date to UTC. I'm using the following:
TZInfo::Timezone.get('US/Eastern').local_to_utc(date)
The problem is this is giving me 20014 as output, instead of the UTC version of the original date. If I try:
TZInfo::Timezone.get('UTC').local_to_utc(date)
I get 2014, which is the correct year but still unexpected output.
Any ideas about what I'm doing wrong, and what I could use to solve the problem?
local_to_utc actually expects a Time or a DateTime instance:
TZInfo::Timezone.get('US/Eastern').local_to_utc(DateTime.parse(date_src))
# => #<DateTime: 2014-07-08T03:10:00+00:00 ((2456847j,11400s,0n),+0s,2299161j)>
From the documentation, you can have a hint on what actually happened:
All methods in TZInfo that operate on a time can be used with either Time or DateTime instances or with nteger timestamps (i.e. as returned by Time#to_i). The type of the values returned will match the the type passed in.
What actually happens is the local_to_utc calls to_i on the input parameter, which on a string returns the parsed integer from the beginning of the string (2014 in your case since date is the string 2014-07-07T23:10:00+00:00), and adds the time difference to it - 18000 for "US/Eastern" (5 hour difference), and 0 for UTC:
date.to_i
# => 2014
TZInfo::Timezone.get('US/Eastern').local_to_utc(date) - date.to_i
# => 18000
TZInfo::Timezone.get('UTC').local_to_utc(date) - date.to_i
# => 0
So the bottom line is - kind of serendipitously you saw this weird behavior, which stems from the compilation of some surprising quirks of the APIs you used...

How do you store a string in MongoDB as a Date type using Ruby?

I have a string that I'm parsing out from log files that looks like the following:
"[22/May/2011:23:02:21 +0000]"
What's the best way (examples in Ruby would be most appreciated, as I'm using the Mongo Ruby driver) to get that stashed into MongoDB as a native Date type?
require 'date' # this is just to get the ABBR_MONTHNAMES list
input = "[22/May/2011:23:02:21 +0000]"
# this regex captures the numbers and month name
pattern = %r{^\[(\d{2})/(\w+)/(\d{4}):(\d{2}):(\d{2}):(\d{2}) ([+-]\d{4})\]$}
match = input.match(pattern)
# MatchData can be splatted, which is very convenient
_, date, month_name, year, hour, minute, second, tz_offset = *match
# ABBR_MONTHNAMES contains "Jan", "Feb", etc.
month = Date::ABBR_MONTHNAMES.index(month_name)
# we need to insert a colon in the tz offset, because Time.new expects it
tz = tz_offset[0,3] + ':' + tz_offset[3,5]
# this is your time object, put it into Mongo and it will be saved as a Date
Time.new(year.to_i, month, date.to_i, hour.to_i, minute.to_i, second.to_i, tz)
A few things to note:
I assumed that the month names are the same as in the ABBR_MONTHNAMES list, otherwise, just make your own list.
Never ever use Date.parse to parse dates it is incredibly slow, the same goes for DateTime.parse, Time.parse, which use the same implementation.
If you parse a lot of different date formats check out the home_run gem.
If you do a lot of these (like you often do when parsing log files), consider not using a regex. Use String#index, #[] and #split to extract the parts you need.
If you want to do this as fast as possible, something like the following is probably more appropriate. It doesn't use regexes (which are useful, but not fast):
date = input[1, 2].to_i
month_name = input[4, 3]
month = Date::ABBR_MONTHNAMES.index(month_name)
year = input[8, 4].to_i
hour = input[13, 2].to_i
minute = input[16, 2].to_i
second = input[19, 2].to_i
tz_offset = input[22, 3].to_i * 60 * 60 + input[25, 2].to_i * 60
Time.new(year, month, date, hour, minute, second, tz_offset)
It takes advantage of the fact that all fields have fixed width (at least I assume they do). So all you need to do is extract the substrings. It also calculates the timezone offset as a number instead of a string.

Resources