How to calculate the day of the week based on unix time - date

I know that there are functions/classes in most programming languages to do that, but I would like to know the calculation.
So: How do I get from the unix time in seconds to a day-number (e.g. 0 for Sunday, 1 for Monday etc.)?
Thanks in advance. BTW: this is my first post on Stack Overflow.

The problem you ask is reasonably easy, compared to how ridiculously complicated other date/time functions can be (e.g. Zeller's congruence).
Unix time is defined as the number of seconds elapsed after January 1, 1970, at 00:00 (midnight) UTC.
You can look up a calendar to find that 1970-01-01 was a Thursday. There are 24 * 60 * 60 = 86400 seconds in a day.
Therefore values 0 to 86399 are Thursday, 86400 to 172799 are Friday, 172800 to 259199 are Saturday, etc. These are blocks of 86400 seconds aligned at 0.
Suppose T is your Unix timestamp. Then floor(T / 86400) tells you the number of days after 1970-01-01. 0 = Thursday January 1st; 1 = Friday January 2nd; 2 = Saturday January 3rd; etc.
Add 4 and modulo 7. Now 0 → 4; 1 → 5; 2 → 6; 3 → 0; 4 → 1; 5 → 2; 6 → 3; 7 → 4; 8 → 5; 9 → 6; 10 → 0; etc. This is your final answer.
In summary: day of week = (floor(T / 86400) + 4) mod 7.
(This assumes that you want the day of week in UTC. If you want to calculate it for another time zone, you need to perform some addition or subtraction of hours and minutes on T first.)

In JavaScript, days of the week are:
0 = Sun
1 = Mon
2 = Tue
3 = Wed
4 = Thu
5 = Fri
6 = Sat
You can use built-in methods:
// Unix epoch, 4 = Thu
new Date(0).getUTCDay()
// Today, 2 = Tue
new Date().getUTCDay()
Or a custom solution (remember to divide getTime() milliseconds by 1000):
// Unix epoch, 4 = Thu
(Math.floor(new Date(0).getTime() / 86400 / 1000) + 4) % 7
// Today, 2 = Tue
(Math.floor(new Date().getTime() / 86400 / 1000) + 4) % 7
Solution (from Geek for Geeks):
function dayOfWeek(d, m, y) {
let t = [0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4];
y -= (m < 3) ? 1 : 0;
return ( y + y/4 - y/100 + y/400 + t[m-1] + d) % 7;
}
// Unix epoch, 4 = Thu
Math.floor(dayOfWeek(1, 1, 1970))
// Today, 2 = Tue
Math.floor(dayOfWeek(7, 12, 2021))
https://www.geeksforgeeks.org/find-day-of-the-week-for-a-given-date/

Related

Total date calculation for a list of date intervals

I have an array of start-end dates (work experience). What I need is to calculate total duration of these experiences.
Example 1:
[ {"startDate": "1999-01-01", "endDate": "1999-12-31"}, {"startDate": "2000-01-01", "endDate": "2000-12-31"} ]
This data should produce this result: 2 Years, 0 Months, 0 Days
Example 2:
[ {"startDate": "1999-01-01", "endDate": "1999-02-28"}, {"startDate": "2000-03-01", "endDate": "2000-05-31"} ]
This data sould produce: 0 Years 5 Months 0 Days
My current code is like this:
int totalDays = 0;
foreach (experience in experiences){
totaldays += experience.endDate.Subtract(experience.startDate);
}
int years = totalDays / 365;
totalDays -= years * 365;
int months = totalDays / 30;
totalDays -= months * 30;
int days = totalDays;
There are 2 problems I'm struggling with:
1: I cannot omit leap days. My result for first example is: 2 Years 0 Months 1 Days (February 29th 2000)
2: I cannot calculate days in months correctly. My result for second example is: 0 Years 5 Months 1 Days (151 / 30)
Is there a correct way to do this?

How to convert Julian dates to and from different representations using integer arithmetic

The question is how to convert dates between different representations using integer arithmetic, specifically between a "Days since year zero ( Jan 1, 0000 )" representation, and either Year/Day or Year/Month/Day forms, in the Julian calendar. The different representations are useful for date input, date display and date arithmetic.
Specifically, a date such as June 5th, 2020 is represented in Year/Month/Day representation as
2020 * 512 + 6 * 32 + 5
or in Year/Day representation as
2020 * 512 + 157 ( June 5th is day 157 in a leap year ).
Yesterday, I wanted to write code to do this, and surprisingly didn't find much help online, so I thought I would document my solution here ( I will be answering my own question ).
First here is code for converting from Year/Day to Days ( the language is very similar to Microsoft SQL Server T-SQL, except variable names do not begin with '#', and there is a 'bool" data type ) :
CREATE FUNCTION [date].[YearDayToDays]( yd int ) RETURNS int AS
BEGIN
-- Given a date in Year/Day representation stored as y * 512 + d where 1 <= d <= 366 ( so d is day in year )
-- returns the number of days since "day zero" (1 Jan 0000)
-- using the Gregorian calendar where days divisible by 4 are leap years, except if divisible by 100, except if divisible by 400.
DECLARE y int, d int, cycle int
-- Extract y and d from yd.
SET y = yd / 512, d = yd % 512 - 1
SET cycle = y / 400, y = y % 400 -- The Gregorian calendar repeats every 400 years.
-- Result days come from cycles, from years having at least 365 days, from leap years and finally d.
-- 146097 is the number of the days in a 400 year cycle ( 400 * 365 + 97 leap years ).
RETURN cycle * 146097
+ y * 365
+ ( y + 3 ) / 4 - ( y + 99 ) / 100 + ( y + 399 ) / 400
+ d
END
Now the opposite conversion, Days to Year/Day:
CREATE FUNCTION [date].[DaysToYearDay]( days int ) returns int as
begin
-- Given a date represented by the number of days since 1 Jan 0000
-- calculate a date in Year/Day representation stored as
-- y * 512 + d where d is 1..366
DECLARE y int, d int, cycle int
-- 146097 is the number of the days in a 400 year cycle ( 400 * 365 + 97 leap years )
SET cycle = days / 146097
SET days = days % 146097
SET y = days / 365
SET d = days % 365
-- Need to adjust d to allow for leap years.
-- Leap years are 0, 4, 8, 12 ... 96, not 100, 104 ... not 200... not 300, 400, 404 ... not 500.
-- Adjustment as function of y is 0 => 0, 1 => 1, 2 =>1, 3 => 1, 4 => 1, 5 => 2 ..
SET d = d - ( y + 3 ) / 4 - ( y + 99 ) / 100 + ( y + 399 ) / 400
IF d < 0
BEGIN
SET y = y - 1
SET d = d + CASE WHEN date.IsLeapYear( y ) THEN 366 ELSE 365 END
END
RETURN date.YearDay( cycle * 400 + y, d + 1 )
END
The auxiliary function date.IsLeapYear:
CREATE FUNCTION [date].[IsLeapYear]( y int ) RETURNS bool AS
BEGIN
RETURN y % 4 = 0 AND ( y % 100 != 0 OR y % 400 = 0 )
END
and date.YearDay :
CREATE FUNCTION [date].[YearMonthDay]( year int, month int, day int ) RETURNS int AS
BEGIN
RETURN year * 512 + month * 32 + day
END
Conversion from Year/Day to Year/Month/Day:
CREATE FUNCTION [date].[YearDayToYearMonthDay]( yd int ) returns int AS
BEGIN
DECLARE y int, d int, leap bool, fdm int, m int, dim int
SET y = yd / 512
SET d = yd % 512 - 1
SET leap = date.IsLeapYear( y )
-- Jan = 0..30, Feb = 0..27 or 0..28
IF NOT leap AND d >= 59 SET d = d + 1
SET fdm = CASE
WHEN d < 31 THEN 0 -- Jan
WHEN d < 60 THEN 31 -- Feb
WHEN d < 91 THEN 60 -- Mar
WHEN d < 121 THEN 91 -- Apr
WHEN d < 152 THEN 121 -- May
WHEN d < 182 THEN 152 -- Jun
WHEN d < 213 THEN 182 -- Jul
WHEN d < 244 THEN 213 -- Aug
WHEN d < 274 THEN 244 -- Sep
WHEN d < 305 THEN 274 -- Oct
WHEN d < 335 THEN 305 -- Nov
ELSE 335 -- Dec
END
SET dim = d - fdm
SET m = ( d - dim + 28 ) / 31
RETURN date.YearMonthDay( y, m+1, dim+1 )
END
The auxiliary function date.YearMonthDay:
CREATE FUNCTION [date].[YearMonthDay]( year int, month int, day int ) RETURNS int AS
BEGIN
RETURN year * 512 + month * 32 + day
END
Finally conversion from Year/Month/Day to Year/Day:
CREATE FUNCTION [date].[YearMonthDayToYearDay]( ymd int ) RETURNS int AS
BEGIN
DECLARE y int, m int, d int
-- Extract y, m, d from ymd
SET d = ymd % 32, m = ymd / 32
SET y = m / 16, m = m % 16
-- Incorporate m into d ( assuming Feb has 29 days ).
SET d = d + CASE
WHEN m = 1 THEN 0 -- Jan
WHEN m = 2 THEN 31 -- Feb
WHEN m = 3 THEN 60 -- Mar
WHEN m = 4 THEN 91 -- Apr
WHEN m = 5 THEN 121 -- May
WHEN m = 6 THEN 152 -- Jun
WHEN m = 7 THEN 182 -- Jul
WHEN m = 8 THEN 213 -- Aug
WHEN m = 9 THEN 244 -- Sep
WHEN m = 10 THEN 274 -- Oct
WHEN m = 11 THEN 305 -- Nov
ELSE 335 -- Dec
END
-- Allow for Feb being only 28 days in a non-leap-year.
IF m >= 3 AND NOT date.IsLeapYear( y ) SET d = d - 1
RETURN date.YearDay( y, d )
END
I hope it's useful to someone, and I hope it's correct - I have tested by generating test ranges of days to check the generated calendar looks correct, with the correct number of days in each month, especially February. The functions do not check whether the input is valid, that is assumed. This is part of a project to implement SQL in C#.

Rolling-window matrix with different intervals between columns

I have a vector of data for 21 years with daily data and want to create a rolling window of 365 days such as the next period stars one month (30 days) after the previous one. In the question, n_interval defines the difference between the first data point of the next window and the last observation of the previous series.
Let's assume my daily data start from Jan. 1 2000, then the first column would be Jan. 1, 2000 -Jan.1, 2001 and the second column starts from Feb. 1, 2000. and ends on Feb. 1, 2001. and ... the last column will cover Jan. 1, 2017 to Jan. 1, 2018. for example if:
vec = [1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17]
for a given variable n_interval = 3, with window_size=5, the output matrix should look like:
mat = [[1 4 7 10 13],
[2 5 8 11 14],
[3 6 9 12 15],
[4 7 10 13 16],
[5 8 11 14 17]]
Given your example vector
vec = [1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17];
we can create an indexing scheme by as follows:
First, we need to determine how many rows there will be in the mat. Assuming we want every element of vec to be expressed in mat at least once then we need to make sure that last index in the last row is greater than or equal to the size of vec. It's fairly easy to see that the index of the last column in mat is described by
last_index = n_interval*(n_rows-1) + n_columns
We want to ensure that last_index >= numel(vec). Substituting in the above expression into the inequality and solving for n_rows gives
n_rows >= (numel(vec) - n_columns)/n_interval + 1
We assign n_rows to be the ceil of this bound so that it is the smallest integer which satisfies the inequality. Now that we know the number of rows we generate the list of starting indices for each row
start_index = 1:n_interval:(n_interval*(n_rows-1)+1);
In the index matrix we want each column to be 1 plus the previous column. In other words we want to offset the column according to the array index_offset = 0:(n_interval-1).
Using bsxfun we generate the index matrix by computing the sums of all pairs between the start_index and index_offset arrays
index = bsxfun(#plus, index_offset, start_index');
The final thing we need to worry about is going out of bounds. To handle this we apply the mod function to wrap the out of bounds indicies:
index_wrapped = mod(index-1, numel(vec))+1;
Then we simply sample the vector according to index_wrapped
mat = vec(index_wrapped);
The complete code is
n_interval = 3;
n_columns = 5;
vec = 1:17;
n_rows = ceil((numel(vec)-n_columns)/n_interval + 1);
start_index = 1:n_interval:(n_interval*(n_rows-1)+1);
index_offset = 0:(n_columns-1);
index = bsxfun(#plus, index_offset, start_index');
index_wrapped = mod(index-1, numel(vec))+1;
mat = vec(index_wrapped);

How to convert a random distributed vector to datetime object in MATLAB

I have a vector with random distributed values from 0 to 10 in increasing value, e.g. [1 3 4 9 10]. How can i convert this vector to a datetime object with time values between e.g. November and December such that these numbers represent the corresponding times in between?
Example, if x = [1 2 3] and I want the time period the whole January, then the output should be [1st January, 15th January, 30th January], according to their relative values.
Example, if x = [0 0.5 9 10] and we have entire January then 0 should map to the first day in January and 10 to the last day in January. 0.5 will map to the date at part 0.5/10 = 1/20 starting from the first January to the last. That date will be approximately 30 * 1 / 20 = 1 day and a half into January. Now, the 9 will in the same way be in position 9 / 10 of 30 days. That is 30 * 9 / 10 = 27. That is the 27th day of January. So the output should be [1st January, 1.5th January, 27th January, 30th January] in datetime format.
You can use datenum and some basic arithmetic to arrive at the following solution:
formatIn = 'dd.mm.yyyy';
d1 = '01.01.2017'; % user input, should be the earlier date
d2 = '31.01.2017'; % user input, should be the later date
x = [0 0.5 5 7 10]; % user input
d1 = datenum(d1,formatIn);
d2 = datenum(d2,formatIn);
daysAfter_d1 = d2-d1;
x = x/max(x);
addDays = round(daysAfter_d1*x);
interpolatedDates = d1 + addDays;
datestr(interpolatedDates,formatIn)
ans =
01.01.2017
03.01.2017
16.01.2017
22.01.2017
31.01.2017

Retrieve Month, Day, Hour, Minute, from a number in minute

i want create a counter that retrieve the number of month, day, hour, minute from a given number in minutes, for example i know that:
60 minutes in an hour
24 hours in a day = 60 x 24 = 1440 minutes
31 days per month
1 month = 24 x 60 x 31 = 44,640 minutes
so if i give for example the number 44640 i want have 1 month 0 day 0 hour 0 minute , or for example if i give 44700 i want have 1 month, 0 day 0 hour 60 minute or 1 month 0 day 1 hour 0 minute
any help please?
int total_minutes = 44640;
int total_hours = total_minutes / 60;
int minutes = total_minutes % 60;
int total_days = total_hours / 24;
int hours = total_hours % 24;
int months = total_days / 31;
int days = total_days % 31;
printf("%d months, %d days, %02d:%02d\n", months, days, hours, minutes);
But that's misleading, since months are not all 31 days. On average, a month in the Gregorian calendar is 30.436875 days (43829.1 minutes), so you could use that figure. For many applications, such calculations just assume that a month is always 30 days. But if your time interval is anchored to a specific point in time, it might be better to use the date at both ends to determine how many whole months there are between them.