datenum series to the end of February - Leap year or not - matlab

I want to create a list of dates that go until the end of February. However, since the end of February changes from 28 to 29 depending on whether there's a leap year, I'm having trouble with how to consider both options.
Here's what I have so far:
date = datenum(years(i),12,01):1:datenum(years(i)+1,02,29);
This case, when run on a year that is not a leap year, ends up counting March 1st instead of ending on Feb. 28th.

Here's a little hack I came up with. You can check whether a year is a leap year quite easily by calculating the number of days between February 28 and March 1, like so:
datenum(years(i), 3, 1) - datenum(years(i), 2, 28)
Checking whether it's larger than 1 would indicate leap year. This 1 or 0 logical MATLAB convention leads to the second part of the hack: this is exactly the number of days you need to add to Feb 28: 0 if not leap year, 1 if leap year. Here, therefore, is the full hack:
date = datenum(years(i),12,01):datenum(years(i)+1,02, ...
28 + ((datenum(years(i)+1,3,1) - datenum(years(i)+1,2,28))>1) );
UPDATE / IMPROVEMENT:
Answer already accepted, but I came up with an even better solution. I didn't realize that datenum simply counts days. In this case, we can simply say that the last day of February is the day before March 1. This yields the following drastic simplification:
date = datenum(years(i),12,01):1:(datenum(years(i)+1,3,1)-1);

Datenum, for good or ill, takes negative and zero numbers. So the last day of February can be written:
datenum(2015, 3, 0)
With a comment explaining this madness, of course.

Related

How to fill the last observations with retime in matlab?

I am interpolating variables from quarterly to monthly frequency in MATLAB. However, when I use retime it doesn't go as far as the end of the sample but it stops 2 months before.
Let me give you an example:
T = datetime(2002,01,01):calquarters:datetime(2019,12,01);
TT = timetable(T', randn(72,1))
x = retime(TT, 'monthly', 'spline') % interpolate
As you can see it gives me back 214 observations rather than 216, November and December 2019 are missing.
How can I fix it?
Thanks!
I don't have enough reputation to add a comment, but TT having 72 quarters instead of 73 means that you are actually storing dates from 1st January 2002 to 1st October 2019 - as the next quarter would start from 1st January 2020, which is then not included in your original array (you can check this by printing TT and checking if this date is included or not).
If this is the case, there is no way for retime to interpolate the missing months, as they aren't in the original matrix (that is, retime cannot interpolate from October to January, since there is no such thing in TT).
Replacing datetime(2019,12,01) with datetime(2020,01,01), as well as replacing randn(72,1) with randn(73,1), might solve your issue.

UTC to GPS time for finding TOW in Simulink

for my project, I need to calculate TOW (Time of week) in Simulink. I know this can be achieved through conversion of UTC time to GPS time.
I have written a simple m-file in Matlab which does the action for me in Matlab as follow:
date_gps_int = 10000*y + 100*m + d
date_gps_str = int2str(date_gps_int)
date_gps_str_to_serial = datenum(date_gps_str,'yyyymmdd')
date_str_format = datestr(date_gps_str_to_serial,'dd-mmmm-yyyy')
Num_Days = daysact('06-jan-1980',date_str_format)
Num_Weeks = Num_Days/7
TOW = Num_Weeks - 1024
My first intention was to use this as a function in simulink. But apparently because of 'datenum' and 'datestr' it is not possible, since simulink does not handle strings.
Now I am wondering if anyone can help me with this issue. Is there any way to calculate TOW from the UTC date in Matlab without using those predefined functions?
I also tried to write an algorithm for calculating number of days since '6 January 1980' and then calculating number of weeks by dividing that by 7. But since I am not very familiar with leap year calculation and I don't really know the formula for these kinds of calculations, my result differs from real TOW.
I would appreciate if anybody can help me on this.
There are three formats handled by Matlab for time: formatted date strings - what datestr outputs -, serial date - scalar double, what datenum outputs - and date vectors (see datevec). Conversion functions work with these three, and the most convenient way to convert individual variables (year, month, etc) to a date is to build a date vector [yyyy mm dd HH MM SS].
date_gps_str_to_serial = datenum([y m d 0 0 0]); % midnight on day y-m-d
date_Jan_6_1980 = datenum([1980 01 06 0 0 0]); % midnight on Jan 6th, 1980
Num_Days = date_gps_str_to_serial - date_Jan_6_1980;
Now, beware of leap seconds...
GPS time is computed form the time elapsed since Jan 6th 1980. Take the number of seconds elapsed since that day, as measured by the satellites' atomic clocks, divide by (24*3600) to get a number of days, the remainder is the time of the day (in seconds since midnight).
But, once in a while, the International Earth Rotation and Reference Systems Service will decide that a day will last one second longer to accommodate for the slowing of Earth rotation. It may happen twice a year, on June 30th or December 31st. The calculation of GPS time is wrong, because it does not take into account that some days last 86401 seconds (so dividing by 24*3600 does not work) and will advance by 1 second with respect to UTC each time this happens. There has been 18 such days since Jan 6th 1980, so one should subtract 18 seconds from GPS time to find UTC time. The next time a leap second may be added is June 2019.

Is there a name for date/time interval format like "1h10m"

It's commonplace even outside of software to communicate time or date intervals in a truncated manner. For example: 1h10m translates to "One hour and ten minutes."
This could be abstracted to a set of rules. For instance: A date interval is represented as a combination of _h, _m, (and so on), where _ characters represent non-negative integers or floats, which are summed into one date interval object.
Mixing days, hours, minutes are allowed. For example, 0.5d1h60m would be a synonym for 14h.
Is there a standard defined out there anywhere that resembles this?
The standard for this is a Duration, defined by ISO 8601.
Note that an Interval is a different concept (also defined by the same ISO), although both are closely related:
A Duration defines an amount of time (like "1 hour and 10 minutes" or "2 years, 3 months and 4 days"). But it doesn't tell you when it starts or ends ("1 hours and 10 minutes" relative to what?). It's just the amount of time, by itself.
An Interval (quoting wikipedia) is "the intervening time between two time points". It has a defined start and end dates, but you can use a Duration to define it, as it can have 4 different formats:
Start and end, such as 2007-03-01T13:00:00Z/2008-05-11T15:30:00Z
Start and duration, such as 2007-03-01T13:00:00Z/P1Y2M10DT2H30M
Duration and end, such as P1Y2M10DT2H30M/2008-05-11T15:30:00Z
Duration only, such as P1Y2M10DT2H30M, with additional context information
Cases 1, 2 and 3 are equivalent (all have the same start and end dates). The only difference is that in cases 2 and 3, the duration P1Y2M10DT2H30M is used to calculate the other date (in case 2, you add it to the start date, and in case 3 you subtract it from the end date).
As you can notice above, the standard format for a Duration is P[n]Y[n]M[n]DT[n]H[n]M[n]S, where:
P is the duration designator (for period) placed at the start of the duration representation.
Y is the year designator that follows the value for the number of years.
M is the month designator that follows the value for the number of months.
W is the week designator that follows the value for the number of weeks.
D is the day designator that follows the value for the number of days.
T is the time designator that precedes the time components of the representation.
H is the hour designator that follows the value for the number of hours.
M is the minute designator that follows the value for the number of minutes.
S is the second designator that follows the value for the number of seconds.
So, "1 year and 10 months" is represented as P1Y10M and "1 hour and 10 minutes" is PT1H10M (note that the T is required to resolve the potencial ambiguity between 1 month (P1M) and 1 minute (PT1M), as they use the same letter M as designator).
As #MattJohnson commented, the math with dates it's not always obvious, so the equivalence between different durations can't be what we normally expect.
For the examples below, I'm using Java 8 (just to show how durations can be tricky). Note that the java.time API uses 2 different classes (Period and Duration), but the idea for both is the same (they're both amounts of time).
A duration of 1 month is equivalent to how many days? It depends:
// one month period
Period oneMonth = Period.parse("P1M");
// January 1st
LocalDate jan = LocalDate.of(2016, 1, 1);
System.out.println(jan); // 2016-01-01
// January 1st plus 1 month period = February 1st
LocalDate feb = jan.plus(oneMonth);
System.out.println(feb); // 2016-02-01
// February 1st plus 1 month period = March 1st
LocalDate mar = feb.plus(oneMonth);
System.out.println(mar); // 2016-03-01
// difference between Jan 1st and Feb 1st = 31 days
System.out.println(ChronoUnit.DAYS.between(jan, feb)); // 31
// difference between Feb 1st and Mar 1st = 29 days (2016 is leap year)
System.out.println(ChronoUnit.DAYS.between(feb, mar)); // 29
So, adding 1 month to January 1st results in February 1st - in this case, 1 month is equivalent 31 days (A.K.A. adding a 1 month duration (P1M) is equivalent to adding a 31 days duration (P31D)), and adding 1 month to February 1st results in March 1st (in this case, 1 month = 29 days, because 2016 is a leap year).
1 day = 24 hours? Not always. If there's a Daylight Saving Time shift involved, you can get strange results:
// 1 day period
Period oneDay = Period.parse("P1D");
// 24 hours period
Duration twentyFourHours = Duration.parse("PT24H");
// in Sao Paulo, summer time starts at Oct 15, at midnight
// getting a date one day before DST change, at 10:00 AM
ZonedDateTime z = ZonedDateTime.of(2017, 10, 14, 10, 0, 0, 0, ZoneId.of("America/Sao_Paulo"));
System.out.println(z); // 2017-10-14T10:00-03:00[America/Sao_Paulo]
// add 1 day - gets the same hour (10:00 AM)
System.out.println(z.plus(oneDay)); // 2017-10-15T10:00-02:00[America/Sao_Paulo]
// add 24 hours - gets 11:00 AM because of DST shift (at midnight, clocks moved forward 1 hour)
System.out.println(z.plus(twentyFourHours)); // 2017-10-15T11:00-02:00[America/Sao_Paulo]
In São Paulo, at October 15th, 2017, DST starts (clocks are moved forward by 1 hour), so:
If you add 24 hours to October 14th at 10 AM, you'll get October 15th at 11 AM
But if you add 1 day, you'll get October 15th at 10 AM
So, in this case, 1 day = 23 hours - it means that adding a 1 day duration (P1D) is equivalent to adding a 23 hours duration (PT23H)
When DST ends, is the opposite: clocks move back 1 hour, and 1 day will be equivalent to 25 hours.
So, the standard defines the format and meaning of the amounts of time concepts, but the equivalence between different durations will depend on the context (although it might sound non-intuitive that 1 day is not always 24 hours, but date/time math is not as obvious as we'd like).
You can use moment: http://momentjs.com/docs/#/durations/
moment.duration(100); // 100 milliseconds
moment.duration(60000).humanize(); // a minute
Read more in the above linked docs. And to get all unit values you may want to use the ISO8601 Format:
moment.duration(1, 'd').toISOString() // "P1D"
For example, "P3Y6M4DT12H30M5S" represents a duration of "three years, six months, four days, twelve hours, thirty minutes, and five seconds".
Read more directly under http://momentjs.com/docs/#/durations/as-iso-string/

MATLAB- Adding Terms In An Array

I am fairly new to programming, and I am have a difficult time with finishing a function to use in my homework assignment. Below I have the code for a function that is intended to take the month entered subtract 1 from it, and add the number of days that are entered. Returning the total number of day. For example, if m=4, days= 3, then it would go through the for loop and add 31+28+31+4. I would greatly appreciate your help. Thank you for your time!
function bday=daysinmonth(m, d)
array=[31 28 31 30 31 30 31 31 30 31 30 31];
for i=1:m-1
md=sum(array(i))
end
%sum=md+d
end
The array holding the number of days for each months is a good starting point. Then I don't understand why you iterate up to the month. What you are looking for is the sum up to the current month, so something like:
md=sum(array(1:m-1));
And yes, then you can add the current day to the accumulated days from previous months with
sum=md+d;
You also want to make sure, that you return the this number with
function sum=daysinmonth(m, d)

Automating a holiday date for any year in Matlab

The code below gives a decimal day for one specific year.
HolidayArrayDate(2) = datenum(2012,01,16,00,00,00); %MartinLutherKingJrBirthday
I am trying to make the holiday more general for an input "dataYear" instead of specifying it as "2012". Martin Luther King Jr Birthday is the third Monday of ever year. When i provide it an input of any year 2010/2011/2012/2013/2014 through "dataYear", it should automatically choose the third Monday in January for me. How would i dot this?
Thank you!
Starting from the first day of the year, 21 days always suffice to find the third Monday. So: get serial date number for first day of the year (with datenum); get day-of-the-week for that and the following 20 days (datestr(..., 'd')); find the first three Mondays (find(...=='M', 3); and finally pick the third one and convert it into date string (datestr):
dataYear = 2012; %// input
f = datenum(dataYear,1,1); %// 1st day of year, in serial date number format
r = find(datestr(f+(0:20), 'd')=='M', 3); %// find three Mondays from that day on
result = datestr(f+r(3)-1); %// third Monday, in date string format