Why doe `later` method lead to infinite range in `Date` range? - date

In Julia, you may generate a date range by month like this:
julia> dr = Date(2014,1,29):Dates.Month(1):Date(2014,07,29)
Date("2014-01-29"):Month(1):Date("2014-07-29")
julia> collect(dr)
7-element Array{Date,1}:
2014-01-29
2014-02-28
2014-03-29
2014-04-29
2014-05-29
2014-06-29
2014-07-29
Date(2014,1,29) is the start date, Dates.Month(1) is the step, Date(2014,07,29) is the end date.
Raku has a method later, but when used in custom generator, it lead to infinite range:
lazy my #dates = Date.new('2014-01-29'), Date.new('2014-02-28'), { $^a.later(:1month) } ... Date.new('2014-07-29')
If I use * >= Date.new('2014-07-29') instead of Date.new('2014-07-29') on the right of ... operator, it works:
lazy my #a = Date.new('2014-01-29'), Date.new('2014-02-28'), { $^a.later(:1month) } ... * >= Date.new('2014-07-29')
2014-01-29
2014-02-28
2014-03-28
2014-04-28
2014-05-28
2014-06-28
2014-07-28
2014-08-28
why the custom generator { $^a.later(:1month) } in the { $^a.later(:1month) } ... Date.new('2014-07-29') doesn't stop at 2014-07-29 and lead to infinite range?

As JJMerelo indicates in the comments, the way that the ... operator works is to continue generating elements based on the left-hand-arguments until the right-hand-argument is (per smartmatching) exactly reached.
For example, if we made a sequence of multiples of 10s,
my #tens = 0, 10, 20 ... 95;
say #tens[10]; # 100
say #tens[11]; # 110
This is because not element of #tens will actually be 95. To determine if an element is the final one, the smartmatch operator (~~) is used. Smartmatching a DateTime with another Datetime returns true if the two represent the same time (which may be different nominal times because of timezones, etc).
For sequences, DateTime is further complicated by the fact that .later and .earlier are not communative, so doing $date.later(:1month).later(:1month) is not guaranteed to give the same result as $date.later(:2month).
The reason that * ≥ DateTime.new(…) is different is that smartmatching for Callable objects (which that technically is, it's whatever code equivalent to anon sub $dt { $dt ≥ DateTime.new(…) } passes the left hand argument to the callable. If you're not 100% sure that a sequence will terminate by reaching an exact value, it's best to use the whatever code approach to ensure a value eventually matches.

Hmmm - for any kids out there trying this, there are some pitfalls to do with "what I mean"... for example when I try this
lazy my #b = Date.new('2014-01-31'), Date.new('2014-02-28'), { $^a.later(:1month) } ... * >= Date.new('2014-07-29')
I get this...
#(2014-01-31 2014-02-28 2014-03-28 ...)
But maybe I wanted the last day of each month, what if 2014 is a leap year, blah, blah
So if you want the last day (or last day -1), then there is also this handy method...
say Date.new('2015-11-24').last-date-in-month;

Related

Powershell cast string to time only

I have created a Powershell/XAML app, that on button press makes a RESTAPI call, parses the JSON response into fields in the app front end. All fine so far.
These fields will be populated with a string representing a time, so "1800" or "2000" etc.
The user can then change this from 1800 to 1900 for example.
This is all fine, and in the background the app will use 1900 to update a setting to be used in a POST back.
However there are other settings that are offset by 90 mins of the time above. I don't want the user to have update each one, which is why I am trying to programmatically.
But try as I might, I cannot take a string of 1800, add 90 mins to it and make the value 1930 (not 1890).
You could parse the input as a DateTime object (ignoring the date part) and then use the AddMinutes method.
$input = '1800'
$hour = $input.Substring(0,2)
$minute = $input.Substring(2,2)
$dateInputStr = "0001-01-01,${hour}:${minute}:00"
[datetime]$dateInput = ([datetime]$dateInputStr)
$dateInput = $dateInput.AddMinutes(90)
$dateInput.ToString("HHmm")
Using [timespan] instances is another option:
$time = '1800'
([timespan] ($time -replace '(?<=^..)', ':') + '01:30').ToString('hhmm') #->'1930'
$time -replace '(?<=^..)', ':' uses the regex-based -replace operator to insert : after the first two characters - see this regex101.com page for an explanation of the regex and the ability to experiment with it.
Due to expressing the results only in terms of hours and minutes, the calculation wraps around at midnight, so that adding '05:30', for instance, would yield '0030'
The RHS operand needn't be cast to [timespan] directly, because the data type of the LHS - with its explicit [timespan] cast - implicitly converts the RHS to [timespan] too, with '01:30' representing 1 hour and 30 minutes, i.e. 90 minutes.
If you want to define the duration to add in terms of 90 minutes, use the following instead (there are analogous static methods for other units, such as ::FromSeconds():
[timespan]::FromMinutes(90)
Alternatively, you can cast a number to [timespan], which is interpreted as ticks, which are 100-nanosecond units; there are 1e9 (10 to the power of 9) nanoseconds in a second, and therefore 1e7 100-nanosecond units in a second. Thus, multiplying with 1e7 gives you seconds, and multiplying that with 60 minutes.
# 90 minutes expressed as ticks
[timespan] 90 * (60 * 1e7)
When I read this question I wanted to solve it with minimal string manipulation, leaning on time related objects and methods instead. datetime was the first object I thought of, but it expects a date (year, month, day). Things actually simplify if we use timespan. Its static method, ParseExact, can parse the string directly.
$offsetTimeSpan = [timespan]::FromMinutes(90)
$timeField = '830'
$timeStr = $timeField.PadLeft(4, '0')
$timeSpan = [timespan]::ParseExact($timeStr, 'hhmm', [CultureInfo]::InvariantCulture)
$offsetTime = $timeSpan.Add($offsetTimeSpan)
$offsetTime.ToString('hhmm')
$timeField is used to represent the time you get from the RESTAPI. PadLeft is only needed if it's possible for a leading 0 to be missing. ParseExact does the heavy lifting of converting the string to a time type. Because timespan doesn't have an AddMinutes member, we use the Add method passing in a timespan of 90 minutes, $offsetTimeSpan.
You don't mention anything about overflowing past midnight. You can test for overflow using $offsetTime.Days, if any special processing is required.

How to reduce code in Swift when dealing with variables and if statements?

I am currently building an app to teach myself Swift so am still very new. I’ve encountered a problem. The app is a timetable creator. I have up to twelve subjects that all have points. These points are then spread across days. I have a concept for code that will allocate the points fine using loops but wondered whether there was something to reduce the amount of code rather than, what I currently have, something like this for each subject:
subject1.monpts = 20
subject1.tuepts = 20
subject1.wedpts = 20
subject1.thurpts = 20
subject1.fripts = 20
subject1.satpts = 20
subject1.sunpts = 20
This, x12, is a lot of code. But I need it so that each subject has an option for points for each day of the week (which the app will then allocate time based on these points). To print the timetable, I am putting each subjectX.daypts together but this means I’m writing out 12 subjects for each day.
I also need to only display something if the variable actually has a value. I plan to do this using if statements but that means writing a statement for every single variable which at the moment is 12 x 7 = 48! E.g. (ignore the formating - just for concept)
if subjects1.monpts = 0 {
subjects1monLabel = isHidden.false
// or just a print / don't print statement
}
I feel as if I'm missing an easier way to do this!
Here is a picture that explains the concept a bit better:
If you want to save information about those fields you can have a dictionary with keys of a enum and values of ints like so:
enum WeekDay: CaseIterable {
case monday, tuesday, wednesday, thursday, friday, saturday, sunday
}
struct Subject {
var pointsForWeekDay: [WeekDay: Int]
}
Now you could do:
var pointsForWeekDay = Dictionary(uniqueKeysWithValues:
WeekDay.allCases.map { weekDay in
return (weekDay, 20)
}
)
var subject = Subject(pointsForWeekDay: pointsForWeekDay)
CaseIterable allows you to access all values of your enum.
Map takes every weekDay and creates an array of tuples with your Int values.
And finally you can combine that to have a complete Dictionary with uniqueKeysWithValues initializer, which takes an array of the produced tuples.
Your whole vision of how to organize this material is upside down. Start by thinking about what all your subjects have in common: points for each of the seven days, label hidden for each of the seven days, and so forth. Now incorporate that into a type (a struct): Subject. Now instead of subjects1..., subjects2... and so forth, you have an Array of Subject.
So: any time you have variables named with a number, that should be an array instead. Any time you have clumps of repeated concepts, that should be a type instead.
Even the notion of the seven days of the week could itself be condensed in the same way. If all we're talking about is points per day, an array of seven numbers would do.
So we'd end up with a skeleton like this:
struct Subject {
var dayPoints : [Int]
}
var myTwelveSubjects : [Subject]
...and you can build that out as more requirements come online, such as whether a day is hidden.

Get months between two dates ignoring the days

I want to count the months between two dates, and only compare with their months while ignoring the days, so 2012-01-31 and 2012-02-01 should have 1 month difference between them.
I do this with joda-time:
import org.joda.time.*;
PeriodType yearMonth = PeriodType.yearMonthDay().withDaysRemoved();
LocalDate dt1 = new LocalDate(2012, 1, 31);
LocalDate dt2 = new LocalDate(2012, 2, 1);
int months = new Period(dt1, dt2, yearMonth).getMonths();
System.out.println(months);
But I got printed output:
0
Although I used .withDaysRemoved(), but it's not working. Do I misuse it?
java.time
The Joda-Time project is now in maintenance mode. The team advises migration to the java.time classes.
LocalDate
As in Joda-Time, a LocalDate represents a date-only value without time-of-day and without a time zone.
LocalDate start = LocalDate.of ( 2012 , Month.JANUARY , 31 );
LocalDate stop = LocalDate.of ( 2012 , Month.MARCH , 1 );
Establish the place to hold our results.
long countMonths = 0;
YearMonth
The YearMonth class represents, well, a year and a month. This is the conduit to considering whole months, as you want, rather than number of days.
YearMonth ymStart = YearMonth.from ( start );
YearMonth ymStop = YearMonth.from ( stop );
This YearMonth class has methods for comparison such as isAfter, isBefore, and equals.
The ChronoUnit class can calculate elapsed months between a pair of Temporal objects. The YearMonth class fortunately implements Temporal and works with ChronoUnit.
if ( ymStart.isAfter ( ymStop ) ) {
// Handle error condition. Unexpected input values.
} else if ( ymStart.equals ( ymStop ) ) {
countMonths = 0;
} else { // Else different months.
countMonths = ChronoUnit.MONTHS.between ( ymStart , ymStop );
}
Dump to console.
System.out.println ( "start: " + start + " | stop: " + stop + " | countMonths: " + countMonths );
start: 2012-01-31 | stop: 2012-03-01 | countMonths: 2
Half-Open
The results above are based on the Half-Open approach to defining a span of time where the beginning is inclusive while the ending is exclusive. This approach is commonly used with date-time work, including throughout the java.time classes.
So, for example, lunch period starts at the first moment of the noon hour and runs up to, but not including, the first moment of 1 PM.
Another example: A week would start on a Monday and run up to, but not including, the following Monday. Or in this case, a pair of year-months from January and going up to, but not including, March; they yield a span of 2 months.
I believe using the Half-Open approach throughout your code leads to more clarity and less bugs. But if you or your users demand otherwise, add one to the results above.
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old date-time classes such as java.util.Date, .Calendar, & java.text.SimpleDateFormat.
The Joda-Time project, now in maintenance mode, advises migration to java.time.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations.
Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport and further adapted to Android in ThreeTenABP (see How to use…).
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.
The month arithmetic of LocalDate will and must always use the day-of-month for its calculations. The fact that you have specified the period type such that the days shall not be used only means: The final result shall not show any days (but the day-of-month-component of LocalDate is internally still used).
However, if you use another type, namely YearMonth, then this type defines a different month arithmetic:
LocalDate dt1 = new LocalDate(2012, 1, 31);
LocalDate dt2 = new LocalDate(2012, 2, 1);
YearMonth ym1 = new YearMonth(dt1.getYear(), dt1.getMonthOfYear());
YearMonth ym2 = new YearMonth(dt2.getYear(), dt2.getMonthOfYear());
PeriodType yearMonth = PeriodType.yearMonthDay();
System.out.println(new Period(ym1, ym2, yearMonth).getMonths()); // 1
System.out.println(new Period(ym1, ym2, yearMonth.withDaysRemoved()).getMonths()); // 1
Here you can also see that - in context of YearMonth - suppressing the days in PeriodType is not relevant.

Convert unix time to month number?

Using os.time how can I get how many months have passed since the unix epoch (Unix Timestamp)
I just need it for a month ID, so any kind of number would be fine, as long as it changes every month, and it can be reversed to get the actual month.
local function GetMonth(seconds)
local dayduration,year = 3600*24
local days={31,0,31,30,31,30,31,31,30,31,30,31}
for i=1970,10000 do -- For some reason too lazy to use while
local yeardays = i%4 == 0 and i%100 ~= 0 and 366 or 365
local yearduration = dayduration * yeardays
if yearduration < seconds then
seconds = seconds - yearduration
else
year = i break
end
end
days[2]=(year%4==0) and 29 or 28
seconds = seconds%(365*24*3600)
for i=1,12 do
if seconds>days[i]*dayduration then
seconds=seconds-days[i]*dayduration
else
return --i + year*12 <-- If you want a unique ID
end
end
end
Currently, it'll give the number 2, since it's February. If you uncomment the code at the end for the unique ID, you'll get 554 instead, meaning we're currently at the 554th month since the epoch.
As Jean-Baptiste Yunès said in his answer's comments, I'm not sure if your sentence:
NOTE: This is for Lua, but I'm unable to use os.date
meant you have no os.date, or that you don't know how to use it. You have an answer for both cases, you can use the one you need.
This may do the trick:
print (os.date("*t",os.time())["month"])
os.time() gives you the current date as a number. os.date("*t",...) converts it into a table in which the month equals to the number of the month corresponding to the date.

Unix gettimeofday() - compatible algorithm for determining week within month?

If I've got a time_t value from gettimeofday() or compatible in a Unix environment (e.g., Linux, BSD), is there a compact algorithm available that would be able to tell me the corresponding week number within the month?
Ideally the return value would work in similar to the way %W behaves in strftime() , except giving the week within the month rather than the week within the year.
I think Java has a W formatting token that does something more or less like what I'm asking.
[Everything below written after answers were posted by David Nehme, Branan, and Sparr.]
I realized that to return this result in a similar way to %W, we want to count the number of Mondays that have occurred in the month so far. If that number is zero, then 0 should be returned.
Thanks to David Nehme and Branan in particular for their solutions which started things on the right track. The bit of code returning [using Branan's variable names] ((ts->mday - 1) / 7) tells the number of complete weeks that have occurred before the current day.
However, if we're counting the number of Mondays that have occurred so far, then we want to count the number of integral weeks, including today, then consider if the fractional week left over also contains any Mondays.
To figure out whether the fractional week left after taking out the whole weeks contains a Monday, we need to consider ts->mday % 7 and compare it to the day of the week, ts->wday. This is easy to see if you write out the combinations, but if we insure the day is not Sunday (wday > 0), then anytime ts->wday <= (ts->mday % 7) we need to increment the count of Mondays by 1. This comes from considering the number of days since the start of the month, and whether, based on the current day of the week within the the first fractional week, the fractional week contains a Monday.
So I would rewrite Branan's return statement as follows:
return (ts->tm_mday / 7) + ((ts->tm_wday > 0) && (ts->tm_wday <= (ts->tm_mday % 7)));
If you define the first week to be days 1-7 of the month, the second week days 8-14, ... then the following code will work.
int week_of_month( const time_t *my_time)
{
struct tm *timeinfo;
timeinfo =localtime(my_time);
return 1 + (timeinfo->tm_mday-1) / 7;
}
Assuming your first week is week 1:
int getWeekOfMonth()
{
time_t my_time;
struct tm *ts;
my_time = time(NULL);
ts = localtime(&my_time);
return ((ts->tm_mday -1) / 7) + 1;
}
For 0-index, drop the +1 in the return statement.
Consider this pseudo-code, since I am writing it in mostly C syntax but pretending I can borrow functionality from other languages (string->int assignment, string->time conversion). Adapt or expand for your language of choice.
int week_num_in_month(time_t timestamp) {
int first_weekday_of_month, day_of_month;
day_of_month = strftime(timestamp,"%d");
first_weekday_of_month = strftime(timefstr(strftime(timestamp,"%d/%m/01")),"%w");
return (day_of_month + first_weekday_of_month - 1 ) / 7 + 1;
}
Obviously I am assuming that you want to handle weeks of the month the way the standard time functions handle weeks of the year, as opposed to just days 1-7, 8-13, etc.