Find the nearest time span - algorithm

I have a requirement where I have say 2 parameters a bucketDelta and a start time and I need to calculate the closest time interval in bucketDelta steps that is less than the given time. (sounds convoluted enough ? Here is an example)
say bucketDelta
15minutes and my time is 13 Sep 7:05 PM - returns 13 Sep 7:00 PM
15minutes and my time is 13 Sep 7:17 PM - returns 13 Sep 7:15 PM
15minutes and my time is 13 Sep 7:35 PM - returns 13 Sep 7:30 PM
...
30 minutes and my time is 13 Sep 7:05 PM - returns 13 Sep 7:00 PM
30 minutes and my time is 13 Sep 7:17 PM - returns 13 Sep 7:00 PM
30 minutes and my time is 13 Sep 7:35 PM - returns 13 Sep 7:30 PM
...
60 minutes and my time is 13 Sep 7:05 PM - returns 13 Sep 7:00 PM
60 minutes and my time is 13 Sep 7:35 PM - returns 13 Sep 7:00 PM
60 minutes and my time is 13 Sep 7:55 PM - returns 13 Sep 7:00 PM
24 Hours and my time is 13 Sep 7:05 PM - returns 13 Sep 12:00 AM
24 Hours and my time is 13 Sep 9:05 PM - returns 13 Sep 12:00 AM
..
Here is the logic I have for this but I am not too happy with a million Ifs. Is there a better way to do this ?
if (bucketDelta == TimeSpan.FromSeconds(900)) {
if (bucketStop.Minute > 0 && bucketStop.Minute < 15)
{
minute = bucketStop.Minute;
}
else if (bucketStop.Minute > 15 && bucketStop.Minute < 30)
{
minute = bucketStop.Minute - 15;
}
else if (bucketStop.Minute > 30 && bucketStop.Minute < 45)
{
minute = bucketStop.Minute - 30;
}
else if (bucketStop.Minute > 45 && bucketStop.Minute < 60)
{
minute = bucketStop.Minute - 45;
}
}else if(bucketDelta == TimeSpan.FromSeconds(1800)) {
if (bucketStop.Minute > 0 && bucketStop.Minute < 30)
{
minute = bucketStop.Minute;
}
else if (bucketStop.Minute > 30 && bucketStop.Minute < 60)
{
minute = bucketStop.Minute - 30;
}
} else if(bucketDelta == TimeSpan.FromSeconds(3600))
{
if (bucketStop.Minute > 0 && bucketStop.Minute < 60)
{
minute = bucketStop.Minute;
}
}
else if (bucketDelta == TimeSpan.FromSeconds(86400))
{
if (bucketStop.Hour > 0 && bucketStop.Hour < 24)
{
minute = (bucketStop.Hour * 60);
}
}
bucketStop = bucketStop.AddMinutes(-1 * minute);

Convert both into integer multiples of a standard unit, divide the absolute time by the length of your bucket, use floor to get an integer, multiply by the length of your bucket, and convert back. Depending on your language, floor may either be implicit from the type system or explicit.
For example in Java your calculation could look something like the following (untested):
long intervals = originalInstant.toEpochMilli() / bucketInMilliseconds;
Instant answer = Instant.fromEpochMilli( bucketInMilliseconds * intervals );

Related

How can this formula to swizzle rows be simplified?

The problem is quite simple to understand but solving it was not as easy as it sounded at first.
Let's assume the following, an image that is 8*4, normal order is easy, you return the pixel index:
// 00 01 02 03 04 05 06 07
// 08 09 10 11 12 13 14 15
// 16 17 18 19 20 21 22 23
// 24 25 26 27 28 29 30 31
Now suppose you want to swizzle rows like so:
// 00 01 02 03 04 05 06 07
// 16 17 18 19 20 21 22 23
// 08 09 10 11 12 13 14 15
// 24 25 26 27 28 29 30 31
I solved it, not without trouble to be honest, with the following formula:
index / 8 % 2 * 16 + index / 16 * 8 + index % 8
Isn't there a simpler formula to get the same result?
Assuming / and % return the quotient and remainder in the Euclidean division:
The classic ordering can be obtained as:
row = n / 8
col = n % 8
And the swizzled ordering can be obtained as:
col = n % 8
old_row = n / 8
new_row = 2 * (old_row / 2) + (1 - (old_row % 2))
Explanation:
2 * (old_row / 2) groups the rows two by two;
(1 - (old_row % 2)) swaps row 0 and row 1 of each group.

Question about the difference between 2 dates, which is the right approach?

I've been recently asked to do a simple exercice to calculate the difference between 2 dates.
first date is the birth date, second date is the actual date (or any date entered as the end date) let's call it "end date".
Format: Year, Month, Day (we don't care about hours for now)
Here is the deal :
The birth date : 2021, 02, 11
The end date : 2022, 02, 10
The difference between these 2 dates is : 11 months and 30 days. That's seems the logic answer but let's try to get a little bit deeper :
11/02 -> 11/03 = 1 month : 17 + 11 = 28 }
11/03 -> 11/04 = 1 month : 20 + 11 = 31 |
11/04 -> 11/05 = 1 month : 19 + 11 = 30 |
11/05 -> 11/06 = 1 month : 20 + 11 = 31 | From February
11/06 -> 11/07 = 1 month : 19 + 11 = 30 | To January
11/07 -> 11/08 = 1 month : 20 + 11 = 31 | 11 months
11/08 -> 11/09 = 1 month : 20 + 11 = 31 | => 334 days
11/09 -> 11/10 = 1 month : 19 + 11 = 30 |
11/10 -> 11/11 = 1 month : 20 + 11 = 31 |
11/11 -> 11/12 = 1 month : 19 + 11 = 30 |
11/12 -> 11/01 = 1 month : 20 + 11 = 31 }
11/01 -> 10/02 ------------> 20 + 10 = 30
This is the reasoning behind the 11 months and 30 days, but there is another approach (correct me if I'm wrong) which is :
the starting stays the same, which is 11/02 so the rest is :
02/2021: 17/28
03/2021: 31/31 }
04/2021: 30/30 |
05/2021: 31/31 |
06/2021: 30/30 |
07/2021: 31/31 |
08/2021: 31/31 | 11 months
09/2021: 30/30 | => 337 days
10/2021: 31/31 |
11/2021: 30/30 |
12/2021: 31/31 |
01/2022: 31/31 }
02/2022: 10/28
There is a difference of 3 days between the 2 dates when using the 2nd approach, and therefore the difference will be
11 month and 27 days.
Which approach do you think is the right one ?

Trying to Sync weekdays between 2 years

I'm trying to come up with something to Sync weekdays between years
So far I can do it for a 4 year gap just by subtracting 364 days
For example
Monday Feb 1 2021 - 364 days becomes Monday Feb 3rd 2020
Friday Feb 19 2021 - 364 days becomes Friday Feb 21nd 2020
Tuesday Mar 2 2021 - 364 days becomes Tuesday Mar 3rd 2020
notice how the weekday is in perfect sync (Monday to Monday, Tuesday to Tuesday etc)
and I can do this for 2 years just by using 728 days (364 * 2)
and so on for 3 and 4 years
my problem is after 4 years it stops working
if I do the same thing for 5 Years (364*5)
Monday Feb 1st 2021 becomes Monday Feb 8th 2016
however I would want it to be Monday Feb 1st 2016
I cant seem to crack how to deal with this for 5 years on
This is using Zeller’s Rule to get the day number, and then just modifying the actual date when subtracting 365 days to get the day name to match. I'm sure there are edge cases (e.g. I believe this would currently allow a result of something like "March 33"), but this should get you started:
const days = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']
const months = ["January", "February", "March", "April", "May", "June",
"July", "August", "September", "October", "November", "December"
];
const dayNum = (day, month, year) => {
if (month <= 2) {
year--;
month += 12;
}
month-=2;
const lastTwoDigitsOfYear = year % 100;
const firstTwoDigitsOfYear = (year - lastTwoDigitsOfYear) / 100
let F = day + Math.floor((13*month-1)/5) + lastTwoDigitsOfYear + Math.floor(lastTwoDigitsOfYear/4) +Math.floor(firstTwoDigitsOfYear/4)-2*firstTwoDigitsOfYear
let f = F >= 0 ? (F % 7) : 7 + (F % 7);
return f
}
// Ok, so we can get the day for any date.
const syncedYearAdd = (day, month, year, numYears) => {
const d1 = dayNum(day, month, year);
const d2 = dayNum(day, month, year + numYears);
if (d1 < d2) {
day -= (d2 - d1)
} else if (d1 > d2) {
day += (d1 - d2);
}
if (day < 0) {
day += 7;
}
console.log(days[d1], day, months[month-1], year + numYears)
}
// Monday Feb 1st 2021
for (let i = 0; i <= 5; i++) {
syncedYearAdd(1, 2, 2021, i * -1)
}

How set epoch on ESP32 and Arduino IDE to update the timedate without external RTC and Wifi?

On my ESP32 I want to have information about actual time without Wifi connection or an external RTC chip. I started with this simple code
time_t now;
struct tm* timeinfo;
void Check_Time(void) {
time(&now);
timeinfo = localtime(&now);
Serial.println(timeinfo);
}
void setup() {
Serial.begin(115200);
}
void loop() {
Check_Time();
delay(1000);
}
It works since the output is
Thu Jan 1 00:07:57 1970
Thu Jan 1 00:07:58 1970
Thu Jan 1 00:07:59 1970
Thu Jan 1 00:08:00 1970
...
and naturally it starts from 1 Jan 1970. Now I want to update this time to the actual one but I haven't found a direct solution. I know that I could convert a date to a time_t data with the mktime function (is it right?) but how I can pass it to the system? How I should manage this problem?
I got it to work by using:
#include <sys/time.h>
// ...
struct timeval tv;
tv.tv_sec = /* seconds since epoch here */;
tv.tv_usec = /* microseconds here */;
settimeofday(&tv, NULL);
Replacing the comments with the variable that stores the times.
I am updating my time over Bluetooth Low Energy.
Here is it working:
1970 1 1 0 0 16
1970 1 1 0 0 17
1970 1 1 0 0 18
Time set
2020 12 6 22 45 32
2020 12 6 22 45 33
2020 12 6 22 45 34

Ruby Determine Season (Fall, Winter, Spring or Summer)

I am working on a script that is supposed to determine the "season" of the year based on date ranges:
For Example:
January 1 - April 1: Winter
April 2 - June 30: Spring
July 1 - September 31: Summer
October 1 - December 31: Fall
I am not sure how the best way (or the best ruby way) to go about doing this. Anyone else run across how to do this?
31 September?
As leifg suggested, here it is in code:
require 'Date'
class Date
def season
# Not sure if there's a neater expression. yday is out due to leap years
day_hash = month * 100 + mday
case day_hash
when 101..401 then :winter
when 402..630 then :spring
when 701..930 then :summer
when 1001..1231 then :fall
end
end
end
Once defined, call it e.g. like this:
d = Date.today
d.season
You could try with ranges and Date objects:
http://www.tutorialspoint.com/ruby/ruby_ranges.htm
without ranges.
require 'date'
def season
year_day = Date.today.yday().to_i
year = Date.today.year.to_i
is_leap_year = year % 4 == 0 && year % 100 != 0 || year % 400 == 0
if is_leap_year and year_day > 60
# if is leap year and date > 28 february
year_day = year_day - 1
end
if year_day >= 355 or year_day < 81
result = :winter
elsif year_day >= 81 and year_day < 173
result = :spring
elsif year_day >= 173 and year_day < 266
result = :summer
elsif year_day >= 266 and year_day < 355
result = :autumn
end
return result
end
Neil Slater's answer's approach is great but for me those dates aren't quite correct. They show fall ending on December 31st which isn't the case in any scenario I can think of.
Using the northern meteorological seasons:
Spring runs from March 1 to May 31;
Summer runs from June 1 to August 31;
Fall (autumn) runs from September 1 to November 30; and
Winter runs from December 1 to February 28 (February 29 in a leap year).
The code would need to be updated to:
require "date"
class Date
def season
day_hash = month * 100 + mday
case day_hash
when 101..300 then :winter
when 301..531 then :spring
when 601..831 then :summer
when 901..1130 then :fall
when 1201..1231 then :winter
end
end
end

Resources