Luxon setZone not working when getting epoch time (valueOf) - datetime

I have been trying to use Luxon to get (for comparison reasons) the epoch miliseconds from two DateTimes in different timezone.
I'm using the .valueOf() method to do so, but even that I'm setting the different timezones for each DateTime, that method always return the same value:
const { DateTime } = require('luxon')
const dtString = '2022-01-15 13:00:00'
const d1 = DateTime.fromSQL(dtString).setZone('America/Sao_Paulo').valueOf()
const d2 = DateTime.fromSQL(dtString).setZone('America/New_York').valueOf()
console.log(d1) // logs 1642262400000
console.log(d2) // logs 1642262400000 (same)
What is wrong?

Instead of parsing the dates in one zone and then shifting the times around, just parse them in the zone you want:
const dtString = '2022-01-15 13:00:00';
const d1 = DateTime.fromSQL(dtString, { zone: "America/Sao_Paulo" }).valueOf();
const d2 = DateTime.fromSQL(dtString, { zone: "America/New_York" }).valueOf();
d1 //=> 1642262400000
d2 //=> 1642269600000
The difference there is that in yours, Luxon parses the string using your system zone. Then you change the zone, but the time is still the time, unless you use keepLocalTime. In mine, I'm telling Luxon what zone to use in interpreting the string, which results in a different time being computed for the two cases.

Based on this Luxon issue, I found the fix for that:
We should use the keepCalendarTime: true option in the setZone method to make it work.
That extra flag says "yes, change the actual time"
So the functional code looks like:
const { DateTime } = require('luxon')
const dtString = '2022-01-15 13:00:00'
const opts = { keepCalendarTime: true }
const d1 = DateTime.fromSQL(dtString).setZone('America/Sao_Paulo', opts).valueOf()
const d2 = DateTime.fromSQL(dtString).setZone('America/New_York', opts).valueOf()
console.log(d1) // logs 1642262400000
console.log(d2) // logs 1642269600000 (prints different value)

Related

Need to convert my Time string to a timestamp to update current timestamp field in firestore

I am trying to convert my Time string that displays in my app as 11:00. I need to convert to a timestamp so I can replace the current Time field in my firestore which is a timestamp.
I have tried using moment.js to update the field but it changes the data type to a string.
Current value in my firestore is shown below
submitJob = () => {
const { navigation } = this.props;
const customer_jobnumber = navigation.getParam('JobNumber', 'No Job Number');
const customer_starttime = navigation.getParam('datetime', 'No Job Start Time');
const customer_end = navigation.getParam('datetimefinish', 'No Job Finish Time');
firebase.firestore().collection("jobs").doc(customer_jobnumber).update({ endtime: customer_end, starttime: customer_starttime, value: firebase.firestore.FieldValue.serverTimestamp() });}
The desired value would be - October 4, 2020 at 11:00:00 AM UTC+1
Found the solution with this, if anyone comes across the same problem.
let tx = customer_starttime.split(":")
let dx = new Date().setHours(parseInt(tx[0]),parseInt(tx[1]),0)
let dl = new Date(dx)

Firebase Cloud function: Weird timestamp bug

So I have implemented Stories in my Flutter+Firebase app, and wrote a Cloud Function in JS to delete all stories older than 24h. I added a test Story in the Database, with a field 'timestamp' and set it to August 25, 8:00. Now when I am running the function, I print out the document id and the timestamp of that found document. However, the dates that get printed out are all in 1973!?
Here is my function:
// Start delete old Stories
const runtimeOpts = {
timeoutSeconds: 300,
memory: '512MB'
}
const MAX_CONCURRENT = 3;
const PromisePool = promisePool.PromisePool;
exports.storiesCleanup = functions.runWith(runtimeOpts).pubsub.schedule('every 1 minutes').onRun(
async context => {
console.log('Cleaning stories...');
await getOldStories();
//const promisePool = new PromisePool(() => deleteOldStories(oldStories), MAX_CONCURRENT);
//await promisePool.start();
console.log("finished cleaning stories");
}
);
async function getOldStories() {
const yesterday = Date.now() - 24*60*60*1000;
console.log("Yesterday: " + yesterday);
var storyPostsRef = admin.firestore().collection("StoryPosts");
var query = storyPostsRef.where("timestamp", "<", yesterday);
storyPostsRef.get().then(
querySnapshot => {
querySnapshot.forEach(
(doc) => {
// HERE I AM PRINTING OUT!
console.log("Found document: " + doc.id + ", which was created on: " + doc.data().timestamp);
//doc.ref.delete();
}
)
return null;
}
).catch(error => {throw error;});
}
//End delete old stories
Here is a picture of a document and its timestamp:
And this is a picture of the id and timestamp printed out for that document:
Edit: So for printing out, I figured that if I print doc.data().timestamp.seconds I get the correct number of seconds since epoch. But I still don't understand what the number 06373393200.000000 (printed in the picture above) is. And how do I then make a query when I want to get all stories where the timestamp is small than today-24h ?
var query = storyPostsRef.where("timestamp", "<", Timesstamp.fromDate(yesterday)); does not work.
If you come to the conclusion that the printed timestamp is from a year other than the one shown in the console, then you are misinterpreting the output. Firestore timestamps are represented with two values - an offset in seconds since the unix epoch, and another offset in nanoseconds from that time. This much is evident from the API documentation for Timestamp.
You're probably taking the seconds offset value and interpreting as an offset in milliseconds, which is common in other timestamp systems. You can see how this would cause problems. If you want to take that a Firestore offset in seconds and use a tool to interpret it in a system that uses milliseconds, you will need to first multiply that value by 1,000,000 to convert seconds to milliseconds.

SwiftUI or Combine Clock/Timer events

Using SwiftUI (or Combine) how might I set up a series of one or more events that are triggered by the (system) clock. Examples might include:
Every night at midnight,
On the hour,
Every fifteen minutes on the quarter hour,
Finally, on a slightly different note: On the 29th of February 2020 at 12:15.
An approximation is easily achieved by setting up a timer event that fires every second and then checking the hours/minutes/seconds, etc. but this seems very inefficient for events that may be many hours or days apart.
I'm looking for something that is closely synchronised to the actual system clock and fires off a single event at the required time rather than firing loads of events and having each one ask "Are we there yet?".
I would suggest the following:
DispatchQueue.global(qos: .background).async {
let isoDate = "2020-01-13T16:58:30+0000"
let dateFormatter = ISO8601DateFormatter()
let date = dateFormatter.date(from:isoDate)!
let t = Timer(fire: date, interval: 2, repeats: true) { timer in
print("fired")
}
let runLoop = RunLoop.current
runLoop.add(t, forMode: .default)
runLoop.run()
}
string to date conversion I used this answer to format the time correctly.
The example is in GMT.
documentation apple you can look up timer tolerance which can be adjusted if you need the timer to be very accurate.
interval is in seconds so this solution won't get more accurate than seconds
You might want to enable the Background Modes capability to go for the very long running timers. Never done that so I can't help here.
All your examples should work. I hope this helps!
I had to implement this feature too using Combine / SwiftUI : a Timer that would execute at start then every day, hour or minutes (for testing), here is my solution if it can be useful or improved :)
class PeriodicPublisher {
var periodicFormat: PeriodicFormat = .daily
init(_ format: PeriodicFormat = .daily) {
self.periodicFormat = format
}
// Must have an equatable for removeDuplicate
struct OutputDate: Equatable {
let compared: String
let original: String
init(_ comparedDatePart: String, _ originalDate: String) {
self.compared = comparedDatePart
self.original = originalDate
}
static func ==(lhs: OutputDate, rhs: OutputDate) -> Bool {
return lhs.compared == rhs.compared
}
}
enum PeriodicFormat {
case daily
case hourly
case minutely
func toComparableDate() -> String {
switch self {
case .daily:
return "yyyy-MM-dd"
case .hourly:
return "HH"
case .minutely:
return "mm"
}
}
}
func getPublisher() -> AnyPublisher<OutputDate, Never> {
let compareDateFormatter = DateFormatter()
compareDateFormatter.dateFormat = self.periodicFormat.toComparableDate()
let originalTimerDateFormatter = DateFormatter()
originalTimerDateFormatter.dateFormat = "yyyy-MM-dd HH:mm"
var nowDate: Just<OutputDate> {
let comparedDate = compareDateFormatter.string(from: Date())
let originalDate = originalTimerDateFormatter.string(from: Date())
return Just(OutputDate(comparedDate, originalDate))
}
let timerDate = Timer.publish(every: 2.0, tolerance: 1.0, on: .main, in: .default, options: nil)
.autoconnect()
.map { dateString -> OutputDate in
return OutputDate(compareDateFormatter.string(from: dateString), originalTimerDateFormatter.string(from: dateString))
}
.eraseToAnyPublisher()
return Publishers.Merge(nowDate, timerDate)
.map { $0 }
.removeDuplicates()
.eraseToAnyPublisher()
}
}
How does it work ?
Every 2 seconds the scheduler issue current date (with Timer.publish()), this date is used to create a "OutputDate" holding two properties : one "comparable" part used to compare if something has changed and one "original" part so it can be useful for the consumer.
Comparable property is Timer's date formatted with toComparableDate given the provided configuration (.daily, .hourly, .minutely). Using "removeDuplicates" on this property allow to publish "OutputDate" only when this value changes. Every day or hour or minute.
Publishers.Merge is used to publish a value immediately after instantiation, otherwise nothing happens before the first Timer.publish(every). Here 2 seconds.
How to use it ?
You would use it with Combine like this :
PeriodicPublisher(.daily).getPublisher().sink { date in
print("Day has changed \(date.original)")
}

node RRule check if rule day is today

I am using 'rrule.js' library in node to parse my RRule. I would like to know if current day is same as rule day. It works on most cases but not all. I also use moment.js to compare. The issue is in "rule.after()". It should include the current day but it doesn't.
function checkIfToday(rruleStr){
var RRule = require('rrule').RRule;
var moment = require('moment');
var rule = RRule.fromString(rruleStr);
// Convert all dates into UTC before comparison
var todayutc = moment().utc(); // today in UTC
var nextOccurrence = rule.after(todayutc,inc=true); // next rule date including today
var nextOccurutc = moment(nextOccurrence).utc(); // convert today into utc
var match = moment(nextOccurutc).isSame(todayutc, 'day'); // check if 'DAY' is same
return match;
}
Any idea what's the best way to do this.
Thanks.
This worked for me. Try setting the time of todayutc back to the beginning of the day using moment's startOf method:
function checkIfToday(rruleStr){
var RRule = require('rrule').RRule;
var moment = require('moment');
var rule = RRule.fromString(rruleStr);
// Convert all dates into UTC before comparison
var todayutc = moment().utc().startOf('day'); // today in UTC
var nextOccurrence = rule.after(todayutc, true); // next rule date including today
var nextOccurutc = moment(nextOccurrence).utc(); // convert today into utc
var match = moment(nextOccurutc).isSame(todayutc, 'day'); // check if 'DAY' is same
return match;
}

Formatting local timestamps with WinRT

WinRT uses the DateTimeFormatter class to turn timestamps into human-readable dates. In C++CX, you'll pass it a DateTime instance, which contains a timestamp in UTC time, and let it work its magic.
However, I have an application that consumes timestamps in local time. I'd like to format them and show them to my users, but if I pass the timestamp as is, the DateTimeFormatter will assume that it's UTC and will try to convert it to local time again, resulting in incorrect times.
How can I display local time with WinRT? Is there a way to turn back local time into UTC time?
The timestamps are generated from the machine that consumes them, so there is no risk of timezone confusion. It would also be technically feasible to produce UTC timestamps instead, but this would be rather inconvenient and I'd like to fall back to that only if it's the only way.
Thankfully, FileTimeToSystemTime, TzSpecificLocalTimeToSystemTime and SystemTimeToFileTime are all available to Windows store apps. With that, it's possible to create a function to change local back to UTC.
uint64 LocalTimeToUtcTime(uint64 local)
{
LARGE_INTEGER largeTime;
largeTime.QuadPart = local;
FILETIME intermediate;
intermediate.dwHighDateTime = largeTime.HighPart;
intermediate.dwLowDateTime = largeTime.LowPart;
SYSTEMTIME systemLocal, systemUtc;
if (!FileTimeToSystemTime(&intermediate, &systemLocal))
{
// handle error
}
if (!TzSpecificLocalTimeToSystemTime(nullptr, &systemLocal, &systemUtc))
{
// handle error
}
if (!SystemTimeToFileTime(&systemUtc, &intermediate))
{
// handle error
}
largeTime.HighPart = intermediate.dwHighDateTime;
largeTime.LowPart = intermediate.dwLowDateTime;
return largeTime.QuadPart;
}
You can use the Windows::Globalization::Calendar class to work with local time, or with time in any time zone.
The Calendar defaults to the local time zone if you don't explicitly set one. You can then use GetDateTime() to retrieve a Windows::Foundation::DateTime instance that can be used with DateTimeFormatter.
Calendar^ cal = ref new Calendar();
cal->SetToMin();
cal->Year = 2014;
cal->Month = 7;
cal->Day = 14;
cal->Hour = 12;
cal->Minute = 34;
cal->Second = 56;
DateTime dt = cal->GetDateTime();
DateTimeFormatter^ dtf = ref new DateTimeFormatter("shortdate shorttime");
String^ result = dtf->Format(dt);
Logger::WriteMessage(result->Data());

Resources