time_format = '%H.%M.%S.%6N'
timestamp = DateTime.now.strftime(time_format) # this works, it shows something like "10.09.53.595977"
DateTime.strptime(timestamp, time_format) # error, in `strptime': invalid date (ArgumentError)
So is it possible to make the #strptime work if I really want to parse the microsecond (6 digits) as well?
Looking at the ruby source code at ext/date/date_strptime.c it seems the N case is taken into account, try this:
DateTime.strptime(timestamp, '%H.%M.%S.%N')
And to check the seconds fraction was parsed try this:
d = DateTime.strptime(timestamp, '%H.%M.%S.%N')
p d.sec_fraction
And compare it with what you have in *time_format*.
Related
One of my first posts, so I'll do my best. I've tried searching this, which is how I got this far..but I could use some help converting some time data in the form mm:ss.000 (that's milliseconds at the end) to seconds with a fraction at the end. For example, 2:15.45 should come out to 135.45.
This works:
t <- "02:15.45" (as.numeric(as.POSIXct(strptime(t, format = "%M:%OS"))) - as.numeric(as.POSIXct(strptime("0", format = "%S"))))
But this one, where I'm trying to use a column of my dataframe (originally in character form) does not work:
starttimesFPsnapjumps <- FPsnapjumps$start (as.numeric(as.POSIXct(strptime(starttimesFPsnapjumps, format = "%M:%OS"))) - as.numeric(as.POSIXct(strptime("0", format = "%S"))))
Perhaps it's because my numbers in the column have an extra 0 - they are mm:ss.000. Any thoughts? Thanks in advance.
I need to format 161901 to 04:19:01PM.
I tried the following:
Time.parse(161901)
"161901".chars.each_slice(2).map(&:join)
Time.parse("161901".chars.each_slice(2).map(&:join))
Being a newbie to ruby, it is difficult to find a way.
Here's is the most basic answer, but it makes some assumptions:
require 'time'
time = Time.strptime('161901', '%H%M%S')
time.strftime('%I:%M:%S%p')
=> "04:19:01PM"
The issue is that your string '161901' may or may not be padded and it might also be an integer and not a string. For example, if the time was 6:00 am, perhaps you get a string such as: '60000', you would need to pad this on the left hand side to parse this properly. Due to this I would suggest the following approach:
require 'time'
# Assume your time is an integer with no right padding:
time = 61901
ptime = Time.strptime(time.to_s.rjust(6, '0'), '%H%M%S') # Do proper padding
ptime.strftime('%I:%M:%S%p')
=> "06:19:00AM"
This should help sanitize your variable that you are parsing to produce consistent results.
References: https://ruby-doc.org/stdlib/libdoc/date/rdoc/DateTime.html#method-i-strftime
DateTime::strptime and DateTime#strftime are purpose-built for this task.
require 'time'
fmt_in = '%H%M%S'
fmt_out = '%I:%M:%S%p'
t = DateTime.strptime('161901', fmt_in)
t.strftime(fmt_out)
#=> "04:19:01PM
You can do like below it was very easy for use multiple times with environment variables if you have fixed display format for time
require 'time'
class Time
def self.strpftime(str, in_format,
out_format = ENV.fetch('out_format'))
strptime(str, in_format).strftime(out_format)
end
end
# with out using environment variable
Time.strpftime('161901', '%H%M%S', '%I:%M:%S%p')
=> "04:19:01PM"
# using environment variable
Time.strpftime('161901', '%H%M%S')
=> "04:19:01PM"
You'll be best off using "strptime" when converting strings to dates or times.
https://ruby-doc.org/stdlib-2.4.1/libdoc/time/rdoc/Time.html#method-c-strptime :
2.5.8 :006 > Time.strptime("161901","%H%M%S")
=> 2020-12-18 16:19:01 +0000
this will get you a "Time" object that you'll be able to query, parse, sort and/or output in different format.
require 'time'
input = '161901'
formatted_input = input.split('').each_slice(2).to_a.map(&:join).join(':')
time = Time.parse(formatted_time)
formatted_time = time.strftime("%I:%M:%S%p")
Output:
=> "04:19:01PM"
I have a TimeSpan that I want to round before adding it to my file.
Sometimes its ok like this: 12:03:55 but sometimes it is like this: 04:12:32.96472749
It should not look like this just give me the seconds so I thought of rounding it up or down it doesnt even matter.
I tried this: ([Math]::Round($result)) => Where $result is the timespan but it is saying that the method is overloaded even though I saw it on StackOverflow like this...
also this does not work either: ([Math]::Round($result,2))
Maybe someone can help me because I think there is a special way to round TimeSpans and not normal decimals.
Edit:
I just checked out String Formatting like this:
$formattedTime = "{0:hh\:mm\:ss}" -f ([TimeSpan] $result)
It looks good but I need to add Days in front if the date goes over 24Hours .. so something like 'dd' maybe?
Ty Faded~
You cannot format a TimeSpan object as if it were a DateTime object.
For that, you need to put together your own format string and use the individual properties you need:
Without days:
$ts = [timespan]::new(0,12,3,55,964.72749)
('{0} {1:D2}:{2:D2}:{3:D2}' -f $ts.Days, $ts.Hours, $ts.Minutes, $ts.Seconds).TrimStart("0 ")
# returns 12:03:55
With days (same format string)
$ts = [timespan]::new(11,12,3,55,964.72749)
('{0} {1:D2}:{2:D2}:{3:D2}' -f $ts.Days, $ts.Hours, $ts.Minutes, $ts.Seconds).TrimStart("0 ")
# returns 11 12:03:55
The time properties of a TimeSpan object are ReadOnly, so you cannot set the Milliseconds to 0 unfortunately.
If you do want to get a 'rounded' TimeSpan object where the Milliseconds are stripped off, you can do this:
$ts = [timespan]::new(0,12,3,55,964.72749)
# create a new TimeSpan object from the properties, leaving out the MilliSeconds
$ts = [timespan]::new($ts.Days, $ts.Hours, $ts.Minutes, $ts.Seconds)
I have an issue where, I'm trying to work out if a certain alert on a webpage is calculating sums correctly. I'm using Capybara and Cucumber.
I have an alert that calculates records that expire within 30 days. When selecting this alert, the records are listed in a table and the date is presented in the following format, "1 feb 2016"
What I want to do is somehow take today's date, compare it to the date returned in the table and ensure that it's >= 30 days from the date in the alert.
I'm able to set today's date as the same format using Time.strftime etc.
When I try things like:
And(/^I can see record "([\d]*)" MOT is calculated due within 30 days$/) do |selection1|
today = Time.now.strftime('%l %b %Y')
thirty_days = (today + 30)
first_30day_mot = first('#clickable-rows > tbody > tr:nth-child(' + selection1 + ') > td:nth-child(3)')
if today + first_30day_mot <= thirty_days
puts 'alert correct'
else
(error handler here)
end
end
As you can see, this is quite a mess.
I keep getting the error TypeError: no implicit conversion of Fixnum into String
If anyone can think of a neater way to do this, please put me out of my misery.
Thanks
There are at least a couple of things wrong with your attempt.
You're converting dates to strings and then trying to compare lengths of time with strings. You should be converting strings to dates and then comparing them
#first returns the element in the page not the contents of the element
It's not 100% clear from your code what you're trying to do, but from the test naming I think you just want to make sure the date in the 3rd td cell (which is in the 1 feb 2016 format) of a given row is less than 30 days from now. If so the following should do what you want
mot_element = first("#clickable-rows > tbody > tr:nth-child(#{selection1}) > td:nth-child(3)")
date_of_mot = Date.parse(mot_element.text)
if (date_of_mot - Date.today) < 30
puts 'alert correct'
else
#error handler
end
Beyond that, I'm not sure why you're using #first with that selector since it seems like it should only ever match one element on the page, so you might want to swap that to #find instead, which would get you the benefits of Capybaras waiting behavior. If you do actually need #first, you might consider passing the minimum: 1 option to make sure it waits a bit for the matching element to appear on the page (if this is the first step after clicking a button to go to a new page for instance)
Convert selection1 to the string explicitly (or, better, use string interpolation):
first_30day_mot = first("#clickable-rows > tbody > tr:nth-child(#{selection1}) > td:nth-child(3)")
Also, I suspect that one line below it should be converted to integer to add it to today:
first_30day_mot.to_i <= 30
UPD OK, I finally got time to take a more thorough look at. You do not need all these voodoo magic with days calculus:
# today = Time.now.strftime('%l %b %Y') # today will be a string " 3 Feb 2016"
# thirty_days = (today + 30) this was causing an error
# correct:
# today = DateTime.now # correct, but not needed
# plus_30_days = today + 30.days # correct, but not needed
first_30day_mot = first("#clickable-rows > tbody > tr:nth-child(#{selection1}) > td:nth-child(3)")
if 30 > first_30day_mot.to_i
...
Hope it helps.
I'd strongly recommend not using Cucumber to do this sort of test. You'll find its:
Quite hard to set up
Has a high runtime cost
Doesn't give enough benefit to justify the setup/runtime costs
Instead consider writing a unit test of the thing that provides the date. Generally a good unit test can easily run 10 to 100 times faster than a scenario.
Whilst with a single scenario you won't experience that much pain, once you have alot of scenarios like this the pain will accumulate. Part of the art of using Cucumber is to get plenty of bang for each scenario you write.
I am working with an API that requires me to pass in numbers as strings. I need to increment the counter on each call.
I am using the following code:
days = days.to_i
days += 1
days = days.to_s
This works, but seems kind of sloppy. Is there a more way to do this in Ruby?
Yes, there is. You can do:
days = days.next
or
days = days.succ
Or, you can use the bang (!) methods:
days.next!
or
days.succ!