I'm doing a date conversion using strptime and it is normalizing my data to always have 2020 as the year and I'm not sure why. Specifically:
value = "2015/03/21"
value2 = Date.strptime(value, '%m/%d/%y')
produces a result where value2 = "2020-03-21" How do I get Date.strptime() to appropriately reflect the year?
The second argument of strptime is the input format in which the date is provided not the expected output format. Therefore change it to:
value = "2015/03/21"
value2 = Date.strptime(value, '%Y/%m/%d')
#=> #<Date: 2015-03-21 ((2457103j,0s,0n),+0s,2299161j)>
In value year is first, month is second. You want to create date object from string, so to correctly parse you should use correct order:
value = "2015/03/21"
value2 = Date.strptime(value, '%Y/%m/%d')
=> Sat, 21 Mar 2015
Related
I'm porting an existing application from Joda-Time to Java 8 java.time.
I ran into a problem where parsing a date/time string that contains a 'day of week' value triggered an exception in my unit tests.
When parsing:
2016-12-21 20:50:25 Wednesday December +0000 3
using format:
yyyy'-'MM'-'dd' 'HH':'mm':'ss' 'EEEE' 'MMMM' 'ZZ' 'e
I get:
java.time.format.DateTimeParseException:
Text '2016-12-21 20:50:25 Wednesday December +0000 3'
could not be parsed: Conflict found:
Field DayOfWeek 3 differs from DayOfWeek 2 derived from 2016-12-21
When letting the DateTimeFormatter indicate what it expects:
String logline = "2016-12-21 20:50:25 Wednesday December +0000";
String format = "yyyy'-'MM'-'dd' 'HH':'mm':'ss' 'EEEE' 'MMMM' 'ZZ";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(format).withLocale(Locale.ENGLISH);;
ZonedDateTime dateTime = formatter.parse(logline, ZonedDateTime::from);
format = "yyyy'-'MM'-'dd' 'HH':'mm':'ss' 'EEEE' 'MMMM' 'ZZ' 'e";
formatter = DateTimeFormatter.ofPattern(format).withLocale(Locale.ENGLISH);
System.out.println(formatter.format(dateTime));
I now get this output:
2016-12-21 20:50:25 Wednesday December +0000 4
So effectively the root cause of the problem is that the e flag in Joda-Time considers Monday to be 1 yet the Java 8 java.time considers Monday to be 0.
Now for the patterns that java.time.DateTimeFormatter supports I find in both the Oracle documentation and in JSR-310 this:
e/c localized day-of-week number/text 2; 02; Tue; Tuesday; T
This explicit example of 2 and 'Tuesday' leads me to believe that Wednesday should also in java.time be 3 instead of 4.
What is wrong here?
Do I misunderstand?
Is this a bug in Java 8?
There's a difference on how Joda-Time and java.time interprets the pattern e.
In Joda-Time, the e pattern designates the numeric value of day-of-week:
Symbol Meaning Presentation Examples
------ ----------- ------------ -------
e day of week number 2
So, using e is equivalent to getting the day of the week from a date object:
// using org.joda.time.DateTime and org.joda.time.format.DateTimeFormat
DateTime d = new DateTime(2016, 12, 21, 20, 50, 25, 0, DateTimeZone.UTC);
DateTimeFormatter fmt = DateTimeFormat.forPattern("e").withLocale(Locale.ENGLISH);
System.out.println(d.toString(fmt)); // 3
System.out.println(d.getDayOfWeek()); // 3
System.out.println(d.dayOfWeek().getAsText(Locale.ENGLISH)); // Wednesday
Note that both the formatter and getDayOfWeek() return 3. The getDayOfWeek() method returns a value defined in DateTimeConstants class, and Wednesday's value is 3 (the third day of the week according to ISO's definition).
In java.time API, the pattern e has a different meaning:
Pattern Count Equivalent builder methods
------- ----- --------------------------
e 1 append special localized WeekFields element for numeric day-of-week
It uses the localized WeekFields element, and this can vary according to the locale. The behaviour might be different when compared to the getDayOfWeek() method:
ZonedDateTime z = ZonedDateTime.of(2016, 12, 21, 20, 50, 25, 0, ZoneOffset.UTC);
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("e", Locale.ENGLISH);
System.out.println(z.format(fmt)); // 4
System.out.println(z.getDayOfWeek()); // WEDNESDAY
System.out.println(z.getDayOfWeek().getValue()); // 3
Note that the formatter uses the localized day of week for English locale, and the value is 4, while calling getDayOfWeek().getValue() returns 3.
That's because e with English locale is equivalent to using a java.time.temporal.WeekFields:
// using localized fields
WeekFields wf = WeekFields.of(Locale.ENGLISH);
System.out.println(z.get(wf.dayOfWeek())); // 4
While getDayOfWeek() is equivalent to using ISO's definition:
// same as getDayOfWeek()
System.out.println(z.get(WeekFields.ISO.dayOfWeek())); // 3
That's because ISO's definition uses Monday as the first day of the week, while WeekFields with English locale uses Sunday:
// comparing the first day of week
System.out.println(WeekFields.ISO.getFirstDayOfWeek()); // MONDAY
System.out.println(wf.getFirstDayOfWeek()); // SUNDAY
So the e pattern might behave differently or not to getDayOfWeek(), according to the locale set in the formatter (or the JVM default locale, if none is set). In French locale, for example, it behaves just like ISO, while in some arabic locales, the first day of the week is Saturday:
WeekFields.of(Locale.FRENCH).getFirstDayOfWeek(); // MONDAY
WeekFields.of(new Locale("ar", "AE")).getFirstDayOfWeek(); // SATURDAY
According to javadoc, the only patterns that return a numeric value for the day of week seem to be the localized ones. So, to parse the input 2016-12-21 20:50:25 Wednesday December +0000 3, you can use a java.time.format.DateTimeFormatterBuilder and join the date/time pattern with a java.time.temporal.ChronoField to indicate the numeric value of the day of week (the ISO non-locale sensitive field):
String input = "2016-12-21 20:50:25 Wednesday December +0000 3";
DateTimeFormatter parser = new DateTimeFormatterBuilder()
// date/time pattern
.appendPattern("yyyy-MM-dd HH:mm:ss EEEE MMMM ZZ ")
// numeric day of week
.appendValue(ChronoField.DAY_OF_WEEK)
// create formatter with English locale
.toFormatter(Locale.ENGLISH);
ZonedDateTime date = ZonedDateTime.parse(input, parser);
Also note that you don't need to quote the -, : and space characters, so the pattern becomes more clear and readable (IMO).
I also set the English locale, because if you don't set, it'll use the JVM default locale, and it's not guaranteed to always be English. And it can also be changed without notice, even at runtime, so it's better to specify one, specially if you already know in what language the input is.
Update: probably the ccccc pattern should work, as it's equivalent to appendText(ChronoField.DAY_OF_WEEK, TextStyle.NARROW_STANDALONE) and in my tests (JDK 1.8.0_144) it returns (and also parses) 3:
DateTimeFormatter parser = DateTimeFormatter
.ofPattern("yyyy-MM-dd HH:mm:ss EEEE MMMM ZZ ccccc", Locale.ENGLISH);
ZonedDateTime date = ZonedDateTime.parse(input, parser);
In Locale.ENGLISH Wednesday is the 4th day of week, as week starts on Sunday.
You can check first day of week with
WeekFields.of(Locale.ENGLISH).getFirstDayOfWeek(); //it's SUNDAY
I have a string that represents a date:
"12.27.1995"
I need to swap the month and the day to get:
"27.12.1995"
I did:
date = "12.27.1995"
month = date[0]+date[1]
day = date[3]+date[4]
date[0] = day[0]
date[1] = day[1]
date[3] = month[0]
date[4] = month[1]
It works good, but looks to bad for me. Is it possible to make it more reliable using less code?
Since your string represents a date, you might want to use a Date object, with strptime to parse the original string and strftime to output it in the desired format:
require 'date'
date = Date.strptime("12.27.1995", "%m.%d.%Y")
puts date.strftime("%d.%m.%Y")
# 27.12.1995
Yes. Perhaps like this:
date = "12.27.1995"
m, d, y = date.split(".")
date = [d, m, y].join(".")
While the answer by #sawa is perfectly valid and should be used here, I would show some technic which is wrong and should not be used here, but might be helpful for anybody to swap two fixed parts of the string:
"12.27.1995".tap { |s| s[0..1], s[3..4] = s[3..4], s[0..1] }
#⇒ "27.12.1995"
Not elegant, but a way using regex captures:
/(\d{1,2})\.(\d{1,2})\.(\d{4})/.match "12.27.1995"
[$2, $1, $3].join('.') #=> "27.12.1995"
I am attempting to change an SQL datetime variable (2016-06-09 14:29:34) into a format that looks like this (00:00_20160601). I have tried to follow a couple of SO questions that will allow me to format a Time object.
This is what I have done so far:
start_datetime = "2016-06-09 14:29:34"
t =Time.new(start_datetime)
t.strftime("%H:%M_%Y%d%m")
This results in the time being formatted to 2016-01-01 00:00:00 +0000, which is obviously not what I want. I was wondering if someone could help me format the datetime object the way I specified?
You can do this with DateTime:
require 'datetime'
DateTime.parse("2016-06-09 14:29:34").strftime("%H:%M_%Y%d%m")
#=> "14:29_20160906"
The format you're feeding in is basically ISO-8601 so it's parsed by default.
Feeding that value into Time.new is completely incorrect. The first argument there is the year, the rest have to be supplied separately. That's why you get 2016-01-01, since everything else comes out as defaults.
Time.new is converting automatically and the result of "2016-06-09 14:29:34".to_i is 2016.
It's not entirely clear why your day value changes from 09 in the input to 01 in the desired output, so I'll use the normal thing and output the same as was input:
require 'time'
start_datetime = "2016-06-09 14:29:34"
t = Time.strptime(start_datetime, '%Y-%m-%d %H:%M:%S')
t.strftime('00:00_%Y%m%d') # => "00:00_20160609"
Since the hours and minutes are being thrown away there are a couple of other ways to go about this.
Ignore the hours and minutes when parsing:
t = Time.strptime(start_datetime, '%Y-%m-%d')
Or use a Date object instead of a Time object:
require 'date'
start_datetime = "2016-06-09 14:29:34"
t = Date.strptime(start_datetime, '%Y-%m-%d')
t.strftime('00:00_%Y%m%d') # => "00:00_20160609"
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
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...