I could use some help with an issue I am facing in a Rails project. I am using the strptime function to return a Date object from an inputted string time and target format:
date = Date.strptime(date, '%Y-%m')
And it seems when I pass in a Date that doesn't match that pattern, i.e. 01-01-24, it does not throw an ArgumentError for me to catch and do anything with. It does catch an invalid input like this: 01-2024 though. Is there a certain kind of validation I can do here to catch this kind of error and check that the RegEx pattern matches?
Date#strptime format is using '%Y-%m' as [year]-[month] so in the case of '01-01-2024' it is seen as [01]-[01]-2024 and parsed to that date structure.
strptime does not respect %Y as having a minimum width so your current expression is essentially equivalent to /\A-?\d+-(?:1[0-2]|0?[1-9])/ (any number of digits followed by a hyphen followed by 1-12 optionally 0 padded)
'01-2024' only raises an error because 20 is not a valid month. For Example: '01-1299' would not raise an error.
Rather than relying on this naivety, you could validate your "date pattern" using a Regexp e.g.
date.match?(/\A\d{4}-(?:1[0-2]|0[1-9])\z/)
Using pry to investigate with:
[22] pry(main)> date = Date.strptime('calimero', '%Y-%m')
Date::Error: invalid date
from (pry):20:in `strptime'
it throws a Date::Error exception
Related
I am using Golang and time.Time to Parse a given string into a time object.
Using RFC3339 and time.Parse here is an example of my code:
t, err := time.Parse(time.RFC3339, "2020-08-08T00:22:44Z07:00")
if err != nil {
return nil, err
}
I get the follow errors.
When I include timezone offset I am getting:
ERRO[0002] parsing time "2020-08-08T00:22:44Z07:00": extra text: 07:00
When I don't include the timezone offset I am getting:
ERRO[0002] parsing time "2020-08-08T00:15:36" as "2006-01-02T15:04:05Z07:00": cannot parse "" as "Z07:00"
How do I avoid this issue when parsing time into a structured object?
The presence of the character Z in the Go time.RFC3339 constant "2006-01-02T15:04:05Z07:00" does not mean that a date conforming to the pattern is supposed to include a Z followed by the time zone offset.
In fact, a date with Z followed by anything else is not a valid RFC3339 date. Hence, your first error extra text: 07:00
The Z stands for "Zulu Time", i.e. UTC time zone. From the RFC3339 specs:
Z A suffix which, when applied to a time, denotes a UTC
offset of 00:00; often spoken "Zulu" from the ICAO
phonetic alphabet representation of the letter "Z".
So the Z alone is already providing the time zone information, that is, UTC.
As #Flimzy noted in the comments, 2020-08-08T00:22:44Z would be a valid RFC3339 date.
t, err := time.Parse(time.RFC3339, "2020-08-08T00:22:44Z")
if err != nil {
panic(err)
}
fmt.Println(t) // 2020-08-08 00:22:44 +0000 UTC
Now, if you read the RFC3339 standard further, you see this definition:
time-zone = "Z" / time-numoffset
time-numoffset = ("+" / "-") time-hour [[":"] time-minute]
Which means that the time zone part of the date is either a Z or the offset. Clearly, since the Z already represents the offset 00:00, you can't have one more +/-HH:mm offset in the same date string.
But this also means that Z or the +/-HH:mm must be present. So if you remove both of them, you get your second error: cannot parse "" as "Z07:00"
The parser is attempting to read the "2020-08-08T00:15:36" string as RFC3339 so it expects either a Z or an offset after the seconds (or milliseconds, if any).
In conclusion, the Z07:00 in the Go time.RFC3339 pattern is just a representation of the fact that the date string is supposed to include a time zone. A valid RFC3339 date string must include either Z or the offset.
In dart I want to do this:
var s = "2018-11-23T04:25:41.9241411Z"; // string comes from a json but represented here for simplicity like this
var d = DateTime.parse(s);
but it throws a null.
Dart can't seem to parse iso 8601 date time formats. I've found a custom serializer called "Iso8601DateTimeSerializer" but how do I add it to my flutter app?
links: https://reviewable.io/reviews/google/built_value.dart/429#-
The instructions here only indicate adding it to dart using "SerializersBuilder.add" but I'm a newbie and cant find out how?
link:
https://pub.dartlang.org/documentation/built_value/latest/iso_8601_date_time_serializer/Iso8601DateTimeSerializer-class.html
The problem is that Dart's DateTime.parse only accepts up to six digits of fractional seconds, and your input has seven.
... and then optionally a '.' followed by a one-to-six digit second fraction.
You can sanitize your input down to six digits using something like:
String restrictFractionalSeconds(String dateTime) =>
dateTime.replaceFirstMapped(RegExp(r"(\.\d{6})\d+"), (m) => m[1]);
Maybe the parse function should just accept more digits, even if they don't affect the value.
Just to add to Irn's answer. You need to add some escapes for the regex to work properly.
String restrictFractionalSeconds(String dateTime) =>
dateTime.replaceFirstMapped(RegExp("(\\.\\d{6})\\d+"), (m) => m[1]);
You need to add it to the serializers builder.
Example:
#SerializersFor(models)
final Serializers serializers = (_$serializers.toBuilder()
..addPlugin(StandardJsonPlugin())
..add(Iso8601DateTimeSerializer()))
.build();
I have string like this
a="{\"company\"=>\"khkhkh\", \"email\"=>\"hjkh#hkkj.kjh\",\"address\"=>\"yiyiyu\", \"date\"=>Mon, 28 Apr 2014 13:14:10 BST +01:00}"
but i have made a mistake when generating this string. that is, i appended the date without converting to string. So now if i try to get back this into a hash using eval(a) . This throws a error, with is acceptable.
SyntaxError: (eval):1: syntax error, unexpected tCONSTANT, expecting => ....
Is there any way to get that hash back, since iam in a situation that i cant regenerate this string.
Any help would be highly appreciable.
Thanks.
For your immediate predicament:
a.gsub(/\"date\"\s*=>(.*?)(\}|,\s*\")/, '"date"=>"\1"\2')
This should work even if the date is not the last entry of the hash.
For the next time around: It is really not a good idea to serialize data by manually turning them into code that you eval later.
In most cases your best bet is probably to just generate JSON and parse that later. Using a proper JSON serializer/generator will also make sure your data is syntactically correct.
If the date is always last you could go with the straightforward approach:
date = a.gsub(/[\{\}]/, '').split('=>').last
a.gsub(date, "\"#{date}\"")
Will return
"{\"company\"=>\"khkhkh\", \"email\"=>\"hjkh#hkkj.kjh\",\"address\"=>\"yiyiyu\", \"date\"=>\"Mon, 28 Apr 2014 13:14:10 BST +01:00\"}"
If you have multiple dates, try to replace them with quoted dates by regexp:
wrong_data = "" # your string
correct_data = wrong_data.gsub(/(\w{3}, \d{2} \w{3} \d{4} \d{2}:\d{2}:\d{2} \w{3} \+\d{2}:\d{2})/, '"\1"')
eval(correct_data)
PS. As #Gene truly noticed, you should avoid using eval in your code.
I have a duration field that is a decimal data type in my database.
My form accepts decimals (e.g. 1.5 hours) but I also want to be able to accept HH:MM (e.g. 1:30 for one hour and thirty minutes).
I'd like to be able to detect HH:MM with regex on before_save in my model and convert it to decimal so that users can enter either decimal or HH:MM. This part is fine and good, but the problem I'm having is testing the regex against the value in the field.
1:30 gets interpreted as data type --- !ruby/class 'BigDecimal' and I can't test it against regex.
Doing .to_s on it converts it to 1.0
How do I get my decimal-typed field to relax and let me convert its value to a string for regex testing in my model?
Here's my code:
# --- Model ---
before_save :convert_duration
def convert_duration
if duration =~ /^([0-9]|0[0-9]|1[0-9]|2[0-3]):[0-5][0-9]$/
time_pieces = duration.split(":")
hours = time_pieces[0].to_i
minutes = (time_pieces[1].to_f/60.0)
# Final value ready for database
self.duration = (hours+minutes).round(1)
end
end
Ruby 1.9.3; Rails 3.2.8
Use the duration_before_type_cast attribute when you want access to the original string.
Docs: http://api.rubyonrails.org/classes/ActiveRecord/Base.html#label-Accessing+attributes+before+they+have+been+typecasted
Doesn't meter what string I pass to parse I'm always getting Illegal Argument exception on GWT DateTimeFormat.parse method.
For instance, what is wrong on the following code line:?
Date date = DateTimeFormat.getFormat("MM-dd-YYYY").parse("10-10-2012");
I get:
java.lang.IllegalArgumentException: 10-10-2012
at com.google.gwt.i18n.shared.DateTimeFormat.parse
Instead of YYYY for the year in the format, you should use yyyy. The format you are specifiying would match a date that looks like: 10-10-YYYY (since Y isn't a special date format character).