Advancing the Date

Hi there-

I know that Date.getDate makes it easy to get the current date or create a date in the future - but I’m wondering if there is a simple tool for adding time to the current date and having it calculate accordingly.

As an example:
If I ran Date.getDate.asSortableString on New Year’s Eve, I’d get a number: 20221231245900. Then, maybe I would want to add 60 seconds, so that the year, day, and hour all turned over.
Simply adding 60 to that number isn’t going to give me an accurate date, so I could parse the string, write a function with information about the year and the months, and so on - but I’m wondering if there is a convenience class that would do something similar.

If anyone knows, I’d appreciate it, thanks.

looks like you can express the date as seconds and do your addition there:

Date.getDate.secStamp.asInteger + 60

If you want to get back to human readable date it I don’t see a method in Date sadly.

You might want to send things out to the date command using the String:unixCmd method

I’m pretty sure this doesn’t quite work either… It seems to return numbers that wouldn’t fit into a normal time-keeping convention… for instance, if you’re at 7 minutes and 20 seconds… and you add 60, you would get a string with “780”. If you exceed 100 seconds in a minute, it simply adds the number in your minutes column.

I can definitely think of a hack-y way to program this, so there’s no urgency - but I was hoping something more elegant existed.

aaarg sorry about that!

you can get seconds since Unix Epoch this way:

  a = Pipe("date +%s","r").getLine; a.close

date ought to be able to parse to and from readable formats for you as well

if you write something nicer post it here!

1 Like

Here’s a rough attempt at a subset of the problem - advancing a .secStamp only.

For incrementing the entire date, I guess I’d have to add logic to test for a leap year, alongside referencing a ‘months’ array where each index held the maximum days for each month.

var incrementSecStamp = {|hhmmss seconds| 
  var wrapCount = {|n max| if (n > max) {n - (max + 1)} {n}}; 
  var addLeadZero = {|n| if (n < 10) {"0" ++ n.asString} {n.asString}};
  var hh, mm, ss, hrs, mins, secs, secPerHr = 3600;
  // seconds values with a total greater than 24hrs are not needed for this
  seconds = seconds % (secPerHr * 24);
  // calculate the amounts to be added to each unit of time
  hrs = (seconds / secPerHr).floor;
  mins = ((seconds - (hrs * secPerHr)) / 60).floor;
  secs = seconds - ((mins * 60) + (hrs * secPerHr));
  // extract values from the input secStamp and sum with the calculated amounts
  ss = hhmmss[4..5].asInteger + secs;
  mm = (hhmmss[2..3].asInteger + mins) + (ss / 60).floor;
  hh = (hhmmss[0..1].asInteger + hrs) + (mm / 60).floor;
  // wrap each value to be within the correct range for 24hr time 
  // and convert to a formatted string
  [wrapCount.(hh, 23), wrapCount.(mm, 59), (ss % 60)]
  .collect({|n| addLeadZero.(n.asInteger)}).join;

a = Date.getDate.secStamp;
incrementSecStamp.(a, 3660);

If you have wslib (Quarks.install("wslib") or see GitHub - supercollider-quarks/wslib: various language additions, GUI classes and moreMain features: SimpleMIDIFile, SVG, RoundButton, SmoothSlider, AutoBackup), then you can do:

d = Date.gmtime;
-> Tue Sep 27 00:23:32 2022

-> 1664238212.6025

// 'fromRawSeconds' is from wslib
e = Date.fromRawSeconds(d.rawSeconds + 10, daylightSavings: 0)
-> Tue Sep 28 00:23:42 2022

gmtime doesn’t take time zone into account. AFAICS, to correct for that, you would need to get an hour offset Date.getDate.hour - Date.gmtime.hour (you could do this once at the beginning of the session, because it’s extremely unlikely to switch time zones in the middle of a session), and then add this offset to the hour (which might require rolling over a day/month/year too).



I’d suggest that we include that .fromRawSeconds method in the main library - seems like a basic requirement of a Date class

1 Like

Hi -

I think there might be a bug somewhere in this chain. There’s a weird discrepancy between Date.gmtime and Date.fromRawSeconds that I can’t explain.

Can anyone confirm this?

d = Date.gmtime;
Date.gmtime;  //Wed Sep 28.
Date.fromRawSeconds(d);  //Wed Sep 29.

Yes, it’s reproducible.

If you read the code, you’ll see that fromRawSeconds makes a SMPTE object from the seconds value, then does Date.fromSMPTE on that. Follow the chain to fromSMPTE it looks like some of the logic could be fragile.

I’m not the author of wslib, though, so maybe the best way is to log a bug report on the github repository (linked above).

There are likely any number of algorithms online to turn a raw timestamp (seconds) into a date. If Excel can do it, so could we… you or someone else could find one of these and implement it.