Correct way to get accurate time in Rust? - unix

I'm trying to get accurate time with:
use chrono::{DateTime, Local, Utc};
use std::time::SystemTime;
fn main() {
println!(
"Local.now() {}",
Local::now().format("%H:%m:%S").to_string()
);
println!("Utc.now() {}", Utc::now().format("%H:%m:%S").to_string());
let system_time = SystemTime::now();
let stime: DateTime<Utc> = system_time.into();
println!("SystemTime.now() {}", stime.format("%H:%m:%S"));
}
However, if I run it:
$ date && target/debug/mybin
Sun Jan 15 04:08:19 PM CET 2023
Local.now() 16:01:19
Utc.now() 15:01:19
SystemTime.now() 15:01:19
I don't know where comes from the shift, but I want to know what's the correct way to get the right time?

The %m token inserts the current month's number, which is 1 because it is January. You probably want %M instead, which inserts the minute number. So you are correctly obtaining the current time, but are incorrectly displaying it by using the month number in the place where you'd expect to see the minute number.
See chrono's strftime documentation for a complete list of formatting codes.

Related

Groovy: Date and Time comparisons with a slight delay

So I have the following script:
import groovy.time.TimeCategory
def dueDate = context.expand( '${Test 4 - create user task#Response#$[\'_embedded\'][\'userTaskDtoList\'][0][\'dueDate\']}' )
def date = new Date(messageExchange.getTimestamp())
use(groovy.time.TimeCategory){
after24Hours = (date + 24.hours).format("yyyy-MM-dd'T'HH:mm:ss'Z'", TimeZone.getTimeZone('UTC')) }
assert dueDate == after24Hours
What I'm trying to do with this is take the date and time from a REST request (dueDate - which comes in UTC format and with a 24h delay) and create a new date and time from the timestamp of the moment when that request has been sent, which is registered from my system. I then convert that time to UTC to accommodate the format from dueDate and add 24h to it. At the end I verify that the date and time from dueDate and after24Hours is the same.
The output does return the same time but in certain cases if there is a delay between the time the request is being sent and the time is received then the assertion will fail. This depends on the server, usually there is a difference of like 1 millisecond but I'm thinking that if the server will be slower at some point this will definitely be bigger.
What could I do to allow some margin of error in the assertion, maybe like a few seconds or even a couple of minutes?
Ok, so I managed to do this:
import groovy.time.*
def dueDate = context.expand( '${Test 4 - create user task#Response#$[\'_embedded\'][\'userTaskDtoList\'][0][\'dueDate\']}' )
def date = new Date(messageExchange.getTimestamp())
use(groovy.time.TimeCategory){
after24Hours = (date + 24.hours).format("yyyy-MM-dd'T'HH:mm:ss'Z'", TimeZone.getTimeZone('UTC'))
def date1 = Date.parse("yyyy-MM-dd'T'HH:mm:ss'Z'", dueDate)
def date2 = Date.parse("yyyy-MM-dd'T'HH:mm:ss'Z'", after24Hours)
TimeDuration difference = TimeCategory.minus(date2, date1)
log.info date1
log.info date2
assert difference < 2.minutes
}
The script seems to work and it does return an error only if the time is longer than the one I've set in the assertion.
Unfortunately I have another issue now.
For some reason, my date output looks like this:
Fri Oct 01 16:24:10 EEST 2021: INFO: Sat Oct 02 13:24:10 EEST 2021
Which is not the correct format. That date should appear in the Zulu format, after all when I parsed the dates that was the format that I used.
Am I missing something?
What could I do to allow some margin of error in the assertion, maybe
like a few seconds or even a couple of minutes?
Instead of asserting that they are equal, you could assert that the difference between them is less than a threshold that you get to define.
If you use something like AssertJ, and I'd recommend you do, then you can do something like the following:
assertThat(dueDate).isCloseTo(after24Hours, within(1, ChronoUnit.MINUTE));
This will give a small margin to the comparison of the dates, and should fix your issue.

How to check if the device's time is between two times in Flutter from Firebase/Firestore?

In the Firestore project, I have documents in a collection containing data for shops, having fields like shopName, shopAddress, startTime(eg. 10 AM) and closeTime(eg. 10 PM) . (all strings for now)
When the user is browsing the app, i have retrieved the data from Firestore of the shops displayed in the app, now i wanna show that the shop is closed when the device's time is not between the startTime and closeTime of the shop. How do i achieve this?
So far I can detect the device's current time using dart package intl using this code:
print("${DateFormat('j').format(DateTime.now())}");
It gives output as follows:
I/flutter (14877): 6 PM
This is in DateFormat, and the data types stored in Firestore are strings.. I dont know how to compare them.. Do let me know if i have to change the data types in Firestore too.
Thank You
I think if you use 24 Hour Time Format and convert startTime, closeTime and actualTime to int or double ( if the shop close at 20:30/8:30pm), then you can easily compare them with if. On your firebase server string format is perfect.
For example you make a map and iterate it, and check if the actualTime is higher than startTime and lower than closeTime.
I have never tried this code, but i think it is going to work.
Map map = {'1am': 1, '2am': 2, '3am': 3, ... , '11pm': 23};
map.entries.forEach((e) {
if(e.key == actualTime) {
if(e.value >= startTime && e.value < closeTime) {
print('Open');
}
else{
print('Closed');
}
}
});
By the way, I think you should use UTC, because if you change the time-zone on your device, your app is going to show that the shop is closed, but in fact the shop is open, just you are in a different time-zone. You can easily implement this with this code.
var now = DateTime.now().toUtc();
Maybe you can create a hash map like this:
hashMap=['12 AM', '1 AM', '2 AM', ... , '11 PM', '12 AM'];
After that you can get the positions of startTime, closeTime and actualTime, and see if the actualTime is between start and close times positions.
Let me know if you want to give you a code example.

Why is moment.js date is 50 years ahead?

Using moment to format a date retrieved from a firestore timestamp. However the date is off by at least a day, and at most, a few months. and the year is off by 50 no matter what.
Here is the firestore timestamp
EDIT: Here is whats logged from lastMsg.seconds:
1581372232
I retrieve the time in seconds in a FlatList's renderItem:
renderItem={({ item, index }) => {
return (
<Components.InboxItem
title={item.withName}
subtitle={item.lastMsg.seconds}
img={item.withImg}
/>
);
And finally inside the component I use moment like so:
const date = moment()
.utc()
.startOf('year')
.seconds(props.subtitle)
.format('MMMM DD YYYY');
While ive tried multiple format configurations, the one that gets it closest to accurate is with .startOf("year"). Even then, date is being displayed as "February 09, 2070". If .startOf() is changed to "month", "day", or "hour", the date gets changed to sometime in march. How can this be fixed to display the date as in firestore?
Looking at the https://firebase.google.com/docs/reference/js/firebase.firestore.Timestamp we can either get JS Date object or use the toMillis method to get milliseconds.
Now the simple moment.js api for converting timestamp to moment object is given here https://momentjs.com/docs/#/parsing/unix-timestamp-milliseconds/
moment(Number);
Now you can apply format on the moment object like below:
moment(Number).format(String);
Your issue with wrong date is may be due to the use of utc and seconds together and not passing timestamp to moment()
Use moment.unix():
const props = {
subtitle: 1581372232
};
const date = moment
.unix(props.subtitle)
.format('MMMM DD YYYY');
console.log(date);
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"></script>
because item.lastMsg.seconds is
The number of seconds of UTC time since Unix epoch 1970-01-01T00:00:00Z

log15 library rounds up epoch time from nanoseconds to seconds for logging

I'd like to have millisecond precision for my logging in my golang project, currently using log15 library
Problem is when I append it to Context, it rounds back up to seconds
newTimeWithMilliseconds := time.Unix(0, time.Now().UnixNano())
return log.FuncHandler(func(r *log.Record) {
r.Ctx = append(r.Ctx, "time", newTimeWithMilliseconds)
nextHandler.Log(r)
})
When I convert it to string newTimeWithMilliseconds.String() it works and I get "2018-09-25 15:07:45.25801232 -0500 PDT", but when I don't, the decimals go away and I get 2018-09-25 15:07:45 -0700 PDT.
I want to keep in Time format though and not use string, anybody have any ideas on why this is happening and how to solve this?
You need to use time.Format to display your time.Time's value with the precision you want. It doesn't loose its precision unless you modify its value, the reason why you see a difference is only due to the layout used by the call for time.Format of whatever is printing your time.
When you use mytime.String(), the layout used is different that the one used by whatever prints your time otherwise.
That's why you need to either use the time.Time value but manipulate the way it is printed, or store it as a formatted string instead.
See Go by example
// Go supports time formatting and parsing via
// pattern-based layouts.
package main
import "fmt"
import "time"
func main() {
p := fmt.Println
// Here's a basic example of formatting a time
// according to RFC3339, using the corresponding layout
// constant.
t := time.Now()
p(t.Format(time.RFC3339))
// Time parsing uses the same layout values as `Format`.
t1, e := time.Parse(
time.RFC3339,
"2012-11-01T22:08:41+00:00")
p(t1)
// `Format` and `Parse` use example-based layouts. Usually
// you'll use a constant from `time` for these layouts, but
// you can also supply custom layouts. Layouts must use the
// reference time `Mon Jan 2 15:04:05 MST 2006` to show the
// pattern with which to format/parse a given time/string.
// The example time must be exactly as shown: the year 2006,
// 15 for the hour, Monday for the day of the week, etc.
p(t.Format("3:04PM"))
p(t.Format("Mon Jan _2 15:04:05 2006"))
p(t.Format("2006-01-02T15:04:05.999999-07:00"))
form := "3 04 PM"
t2, e := time.Parse(form, "8 41 PM")
p(t2)
// For purely numeric representations you can also
// use standard string formatting with the extracted
// components of the time value.
fmt.Printf("%d-%02d-%02dT%02d:%02d:%02d-00:00\n",
t.Year(), t.Month(), t.Day(),
t.Hour(), t.Minute(), t.Second())
// `Parse` will return an error on malformed input
// explaining the parsing problem.
ansic := "Mon Jan _2 15:04:05 2006"
_, e = time.Parse(ansic, "8:41PM")
p(e)
}
Outputs
2009-11-10T23:00:00Z
2012-11-01 22:08:41 +0000 UTC
11:00PM
Tue Nov 10 23:00:00 2009
2009-11-10T23:00:00+00:00
0000-01-01 20:41:00 +0000 UTC
2009-11-10T23:00:00-00:00
parsing time "8:41PM" as "Mon Jan _2 15:04:05 2006": cannot parse "8:41PM" as "Mon"
Try it out yourself here

How do I go from a NaiveDate to a specific TimeZone with Chrono?

I am parsing dates and times in Rust using the chrono crate. The dates and times are from a website in which the date and time are from different sections of the page.
The date is shown in the format %d/%m/%Y (example: 27/08/2018). The time is shown with only the hour (example: 12, 10, 21, etc.)
I want to store these datetimes as UTC so that I can compute time remaining until a given datetime from now in a "timezone agnostic" way. I know which timezone these datetimes are from (Paris time).
I created a NaiveDate from the date input (this is a work in progress so there's no error handling yet):
let naive_date = NaiveDate::parse_from_str(date, "%d/%m/%Y").unwrap()
From that point on, what would be the best way to get the UTC DateTime, given that I have a string with the hour?
I am lost in the various TimeZone/Offset traits, and do not know if I should use a Local, or FixedOffset and then convert to Utc.
The Chrono documentation could probably be improved to make it easier to find how to do these things.
Assuming this is your starting point:
use chrono::{DateTime, FixedOffset, NaiveDate, NaiveDateTime, NaiveTime, TimeZone, Utc};
// The date you parsed
let date = NaiveDate::from_ymd(2018, 5, 13);
// The known 1 hour time offset in seconds
let tz_offset = FixedOffset::east(1 * 3600);
// The known time
let time = NaiveTime::from_hms(17, 0, 0);
// Naive date time, with no time zone information
let datetime = NaiveDateTime::new(date, time);
You can then use the FixedOffset to construct a DateTime:
let dt_with_tz: DateTime<FixedOffset> = tz_offset.from_local_datetime(&datetime).unwrap();
If you need to convert it to a DateTime<Utc>, you can do this:
let dt_with_tz_utc: DateTime<Utc> = Utc.from_utc_datetime(&dt_with_tz.naive_utc());
I've discovered chrono-tz and found it much easier to use. For example:
pub fn create_date_time_from_paris(date: NaiveDate, time: NaiveTime) -> DateTime<Utc> {
let naive_datetime = NaiveDateTime::new(date, time);
let paris_time = Paris.from_local_datetime(&naive_datetime).unwrap();
paris_time.with_timezone(&Utc)
}
The dates and times are from a website in which the date and time are from different sections of the page.
Here's an example of how you can incrementally parse multiple values from distinct strings, provide default values for unparsed information, and use Chrono's built-in timezone conversion.
The key is to use the parse function to update a Parsed struct. You can use the StrftimeItems iterator to continue to use more readable format strings.
extern crate chrono;
use chrono::prelude::*;
fn example(date: &str, hour: &str) -> chrono::ParseResult<DateTime<Utc>> {
use chrono::format::{self, strftime::StrftimeItems, Parsed};
// Set up a struct to perform successive parsing into
let mut p = Parsed::default();
// Parse the date information
format::parse(&mut p, date.trim(), StrftimeItems::new("%d/%m/%Y"))?;
// Parse the time information and provide default values we don't parse
format::parse(&mut p, hour.trim(), StrftimeItems::new("%H"))?;
p.minute = Some(0);
p.second = Some(0);
// Convert parsed information into a DateTime in the Paris timezone
let paris_time_zone_offset = FixedOffset::east(1 * 3600);
let dt = p.to_datetime_with_timezone(&paris_time_zone_offset)?;
// You can also use chrono-tz instead of hardcoding it
// let dt = p.to_datetime_with_timezone(&chrono_tz::Europe::Paris)?;
// Convert to UTC
Ok(dt.with_timezone(&Utc))
}
fn main() {
let date = "27/08/2018";
let hour = "12";
println!("dt = {:?}", example(date, hour)); // Ok(2018-08-27T11:00:00Z)
}

Resources