www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - What's a good wat to trunctate a time point

reply Dukc <ajieskola gmail.com> writes:
I have a time point, be it SysTime or DateTime, whatever. I want 
to trunctate it to weeks, eg. I want it to become the first point 
of time during the week it was representing. What's a good way to 
do that? Only hacks came to my mind.

The solution does not have to be generic, trough I'd prefer it to 
be if it can be without much extra work.
May 05
parent reply Biotronic <simen.kjaras gmail.com> writes:
On Friday, 5 May 2017 at 08:02:15 UTC, Dukc wrote:
 I have a time point, be it SysTime or DateTime, whatever. I 
 want to trunctate it to weeks, eg. I want it to become the 
 first point of time during the week it was representing. What's 
 a good way to do that? Only hacks came to my mind.

 The solution does not have to be generic, trough I'd prefer it 
 to be if it can be without much extra work.
Here's an implementation that supports start of year, month, week, day, hour, minute and second. Works for DateTime and SysTime. Not heavily tested (all tests included): import std.datetime; DateTime startOf(string unit, DayOfWeek start = DayOfWeek.sun)(DateTime dt) { static if (unit == "year") { return DateTime(dt.year, 1, 1); } else static if (unit == "month") { return DateTime(dt.year, dt.month, 1); } else static if (unit == "week") { auto delta = dt.dayOfWeek - start; if (delta < 0) delta += 7; return DateTime(dt.year, dt.month, dt.day) - dur!"days"(delta); } else static if (unit == "day") { return DateTime(dt.year, dt.month, dt.day); } else static if (unit == "hour") { return DateTime(dt.year, dt.month, dt.day, dt.hour); } else static if (unit == "minute") { return DateTime(dt.year, dt.month, dt.day, dt.hour, dt.minute); } else static if (unit == "second") { return DateTime(dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second); } } SysTime startOf(string unit)(SysTime st) { return SysTime(startOf!unit(cast(DateTime)st), st.timezone); } unittest { auto now = DateTime(2017, 5, 5, 10, 39, 17); auto expectedYear = DateTime(2017, 1, 1, 0, 0, 0); auto expectedMonth = DateTime(2017, 5, 1, 0, 0, 0); auto expectedWeek = DateTime(2017, 4, 30, 0, 0, 0); auto expectedDay = DateTime(2017, 5, 5, 0, 0, 0); auto expectedHour = DateTime(2017, 5, 5, 10, 0, 0); auto expectedMinute = DateTime(2017, 5, 5, 10, 39, 0); auto expectedSecond = DateTime(2017, 5, 5, 10, 39, 17); auto startOfYear = now.startOf!"year"; auto startOfMonth = now.startOf!"month"; auto startOfWeek = now.startOf!"week"; auto startOfDay = now.startOf!"day"; auto startOfHour = now.startOf!"hour"; auto startOfMinute = now.startOf!"minute"; auto startOfSecond = now.startOf!"second"; assert(expectedYear == startOfYear); assert(expectedMonth == startOfMonth); assert(expectedWeek == startOfWeek); assert(expectedDay == startOfDay); assert(expectedHour == startOfHour); assert(expectedMinute == startOfMinute); assert(expectedSecond == startOfSecond); now = DateTime(2017, 4, 30, 10, 39, 17); auto expectedWeek2 = DateTime(2017, 4, 24, 0, 0, 0); auto startOfWeek2 = now.startOf!("week", DayOfWeek.mon); auto expectedWeek3 = DateTime(2017, 4, 29, 0, 0, 0); auto startOfWeek3 = now.startOf!("week", DayOfWeek.sat); assert(startOfWeek2 == expectedWeek2); assert(startOfWeek3 == expectedWeek3); }
May 05
next sibling parent Dukc <ajieskola gmail.com> writes:
On Friday, 5 May 2017 at 09:14:21 UTC, Biotronic wrote:
 Here's an implementation that supports start of year, month, 
 week, day, hour, minute and second. Works for DateTime and 
 SysTime. Not heavily tested (all tests included):

 [lots of code]
Wow! You might want to create a pr to phobos from that -It is so general, and despite what you say I have seen much worse tested stuff there. Thanks for the reply.
May 05
prev sibling parent Biotronic <simen.kjaras gmail.com> writes:
On Friday, 5 May 2017 at 09:14:21 UTC, Biotronic wrote:
 Here's an implementation that supports start of year, month, 
 week, day, hour, minute and second. Works for DateTime and 
 SysTime. Not heavily tested (all tests included):
As the last sentence says, there were holes in the testing, specifically for unsupported units. Updated: import std.datetime; DateTime startOf(string unit, DayOfWeek start = DayOfWeek.sun)(DateTime dt) { static if (unit == "year") { return DateTime(dt.year, 1, 1); } else static if (unit == "month") { return DateTime(dt.year, dt.month, 1); } else static if (unit == "week") { auto delta = dt.dayOfWeek - start; if (delta < 0) delta += 7; return DateTime(dt.year, dt.month, dt.day) - dur!"days"(delta); } else static if (unit == "day") { return DateTime(dt.year, dt.month, dt.day); } else static if (unit == "hour") { return DateTime(dt.year, dt.month, dt.day, dt.hour); } else static if (unit == "minute") { return DateTime(dt.year, dt.month, dt.day, dt.hour, dt.minute); } else static if (unit == "second") { return DateTime(dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second); } else { static assert(false, "\"" ~ unit ~ "\" is not a valid time unit for startOf().\nPlease use one of \"year\", \"month\", \"week\", \"day\", \"hour\", \"minute\" or \"second\""); } } SysTime startOf(string unit)(SysTime st) { return SysTime(startOf!unit(cast(DateTime)st), st.timezone); } unittest { auto now = DateTime(2017, 5, 5, 10, 39, 17); auto expectedYear = DateTime(2017, 1, 1, 0, 0, 0); auto expectedMonth = DateTime(2017, 5, 1, 0, 0, 0); auto expectedWeek = DateTime(2017, 4, 30, 0, 0, 0); auto expectedDay = DateTime(2017, 5, 5, 0, 0, 0); auto expectedHour = DateTime(2017, 5, 5, 10, 0, 0); auto expectedMinute = DateTime(2017, 5, 5, 10, 39, 0); auto expectedSecond = DateTime(2017, 5, 5, 10, 39, 17); auto startOfYear = now.startOf!"year"; auto startOfMonth = now.startOf!"month"; auto startOfWeek = now.startOf!"week"; auto startOfDay = now.startOf!"day"; auto startOfHour = now.startOf!"hour"; auto startOfMinute = now.startOf!"minute"; auto startOfSecond = now.startOf!"second"; assert(expectedYear == startOfYear); assert(expectedMonth == startOfMonth); assert(expectedWeek == startOfWeek); assert(expectedDay == startOfDay); assert(expectedHour == startOfHour); assert(expectedMinute == startOfMinute); assert(expectedSecond == startOfSecond); now = DateTime(2017, 4, 30, 10, 39, 17); auto expectedWeek2 = DateTime(2017, 4, 24, 0, 0, 0); auto startOfWeek2 = now.startOf!("week", DayOfWeek.mon); auto expectedWeek3 = DateTime(2017, 4, 29, 0, 0, 0); auto startOfWeek3 = now.startOf!("week", DayOfWeek.sat); auto expectedWeek4 = DateTime(2017, 4, 30, 0, 0, 0); auto startOfWeek4 = now.startOf!("week", DayOfWeek.sun); assert(startOfWeek2 == expectedWeek2); assert(startOfWeek3 == expectedWeek3); assert(startOfWeek4 == expectedWeek4); assert(!__traits(compiles, now.startOf!"fortnight")); }
May 10