How to get a datetime's offset from UTC? - winapi

Given a datetime that is "local" (i.e. has no timezone information), e.g.:
| Datetime |
|---------------------|
| 2019-01-21 09:00:00 |
| 2019-02-21 09:00:00 |
| 2019-03-21 09:00:00 |
| 2019-04-21 09:00:00 |
| 2019-05-21 09:00:00 |
| 2019-06-21 09:00:00 |
| 2019-07-21 09:00:00 |
| 2019-08-21 09:00:00 |
| 2019-09-21 09:00:00 |
| 2019-10-21 09:00:00 |
| 2019-11-21 09:00:00 |
| 2019-12-21 09:00:00 |
How can i get that date's offset from UTC? (assuming the machine local timezone information)
For example, my local PC is in the Eastern timezone. And the Eastern timezone is either:
300 minutes (5 hours) behind UTC
240 minutes (4 hours) behind UTC
depending on whether "daylight saving" was in effect at the time of that datetime.
Which means for the above list:
| Datetime | Offset from UTC (minutes) |
|---------------------|----------------------------|
| 2019-01-21 09:00:00 | -300 (-5 hours) |
| 2019-02-21 09:00:00 | -300 (-5 hours) |
| 2019-03-21 09:00:00 | -240 (-4 hours) | Daylight savings
| 2019-04-21 09:00:00 | -240 (-4 hours) | Daylight savings
| 2019-05-21 09:00:00 | -240 (-4 hours) | Daylight savings
| 2019-06-21 09:00:00 | -240 (-4 hours) | Daylight savings
| 2019-07-21 09:00:00 | -240 (-4 hours) | Daylight savings
| 2019-08-21 09:00:00 | -240 (-4 hours) | Daylight savings
| 2019-09-21 09:00:00 | -240 (-4 hours) | Daylight savings
| 2019-10-21 09:00:00 | -240 (-4 hours) | Daylight savings
| 2019-11-21 09:00:00 | -300 (-5 hours) |
| 2019-12-21 09:00:00 | -300 (-5 hours) |
And, of course, those offsets change if the dates are from before 2007, the answer changes:
| Datetime | Offset from UTC (minutes) |
|---------------------|----------------------------|
| 2006-01-21 09:00:00 | -300 (-5 hours) |
| 2006-02-21 09:00:00 | -300 (-5 hours) |
| 2006-03-21 09:00:00 | -240 (-5 hours) |
| 2006-04-21 09:00:00 | -240 (-4 hours) | Daylight savings
| 2006-05-21 09:00:00 | -240 (-4 hours) | Daylight savings
| 2006-06-21 09:00:00 | -240 (-4 hours) | Daylight savings
| 2006-07-21 09:00:00 | -240 (-4 hours) | Daylight savings
| 2006-08-21 09:00:00 | -240 (-4 hours) | Daylight savings
| 2006-09-21 09:00:00 | -240 (-4 hours) | Daylight savings
| 2006-10-21 09:00:00 | -240 (-5 hours) |
| 2006-11-21 09:00:00 | -300 (-5 hours) |
| 2006-12-21 09:00:00 | -300 (-5 hours) |
And the answer would be different again during the 1977 energy crisis, as the country ran on daylight saving year round:
| Datetime | Offset from UTC (minutes) |
|---------------------|----------------------------|
| 1977-01-21 09:00:00 | -240 (-4 hours) | Daylight savings
| 1977-02-21 09:00:00 | -240 (-4 hours) | Daylight savings
| 1977-03-21 09:00:00 | -240 (-4 hours) | Daylight savings
| 1977-04-21 09:00:00 | -240 (-4 hours) | Daylight savings
| 1977-05-21 09:00:00 | -240 (-4 hours) | Daylight savings
| 1977-06-21 09:00:00 | -240 (-4 hours) | Daylight savings
| 1977-07-21 09:00:00 | -240 (-4 hours) | Daylight savings
| 1977-08-21 09:00:00 | -240 (-4 hours) | Daylight savings
| 1977-09-21 09:00:00 | -240 (-4 hours) | Daylight savings
| 1977-10-21 09:00:00 | -240 (-4 hours) | Daylight savings
| 1977-11-21 09:00:00 | -240 (-4 hours) | Daylight savings
| 1977-12-21 09:00:00 | -240 (-4 hours) | Daylight savings
And before 1966 the answers change some more.
Windows knows all these things.
So the question is:
given a datetime in FILETIME format
assumed to be of the timezone of the current PC
how can i get that datetime's offset from UTC
at the time of the datetime
In other words:
//Pesudocode. It may look like C#, but i'm using the native Win32 api
Int32 GetDateTimeMinutesOffsetFromUTC(DateTime value)
{
//2006-03-21 09:00:00 ==> -300
//2007-03-21 09:00:00 ==> -240
return -1; //todo
}
or
function GetDateTimeMinutesOffsetFromUtc(Value: TDateTime): Integer;
begin
//2006-03-21 09:00:00 ==> -300
//2007-03-21 09:00:00 ==> -240
Result := -1; //todo
end;
or
int GetDateTimeMinutesOffsetFromUtc(FILETIME value)
{
//2006-03-21 09:00:00 ==> -300
//2007-03-21 09:00:00 ==> -240
Result := -1; //todo
}
And, as a reminder, i'm using the Win32 api.
This is not C/C++ (i.e. i don't have access to the C standard library)
This is not C# (i.e. i don't have access to the .NET Framework Class Library)
This is not Java (i.e. i don't have access to the Java Class Library)
This is not Python
This is not Javascript, React, Rust, Django
I'm talking about Windows and the Win32 API.
SQL Server
You can see the above work in SQL Server:
SELECT
EventDate,
DATEDIFF(minute, CAST(EventDate AS datetime) AT TIME ZONE 'Eastern Standard Time', EventDate) AS MinutesOffsetFromUTC
FROM (VALUES
('2019-01-21 09:00:00.000'),
('2019-02-21 09:00:00.000'),
('2019-03-21 09:00:00.000'),
('2019-04-21 09:00:00.000'),
('2019-05-21 09:00:00.000'),
('2019-06-21 09:00:00.000'),
('2019-07-21 09:00:00.000'),
('2019-08-21 09:00:00.000'),
('2019-09-21 09:00:00.000'),
('2019-10-21 09:00:00.000'),
('2019-11-21 09:00:00.000'),
('2019-12-21 09:00:00.000')
) foo(EventDate)
EventDate MinutesOffsetFromUTC
----------------------- --------------------
2019-01-21 09:00:00.000 -300
2019-02-21 09:00:00.000 -300
2019-03-21 09:00:00.000 -240
2019-04-21 09:00:00.000 -240
2019-05-21 09:00:00.000 -240
2019-06-21 09:00:00.000 -240
2019-07-21 09:00:00.000 -240
2019-08-21 09:00:00.000 -240
2019-09-21 09:00:00.000 -240
2019-10-21 09:00:00.000 -240
2019-11-21 09:00:00.000 -300
2019-12-21 09:00:00.000 -300
(12 rows affected)
Research Effort
Most of the Winapi functions for converting "local" to "UTC", and back again, don't take into account the date in question; but instead only use whether daylight savings is in effect right now:
Functions like FileTimeToLocalFileTime apply the current Daylight Savings Time (DST) bias rather than the bias that was in effect at the time in question.
Others take into account the date being converted, but only look at the daylight saving start and end rules as they are now - not what the rules were then.
But TzSpecificLocalTimeToSystemTime is the one function that does understand datetimes and daylight savings:
TzSpecificLocalTimeToSystemTime takes into account whether daylight saving time (DST) is in effect for the local time to be converted.
In reality Windows doesn't know everything. It keeps the database of historical "daylight savings" dates in the registry:
So for me all it really know is
before the great change of 2007
and after
But it's good enough for me in my use case. And it's good enough for SQL Server.
Bonus Reading
Raymond Chens blog posts tagged with time

Alright, statue of limitations has expired. I gave everyone every opportunity to answer the question themselves, providing all kinds of hints, so someone else could get the sweet sweet reputation.
That time has passed. Now it's time to answer the question because it's what Joel and Jeff would have wanted.
Pseudo-code:
int GetDateTimeOffsetFromUtcMinutes(DateTime localDateTime)
{
//All code on Stackoverflow is public domain; no attribution is ever required.
/*
Given a datetime, tell me how many minutes offset it was from UTC.
2006-03-21 09:00:00 ==> -300 (before daylight savings rules changed)
2007-03-21 09:00:00 ==> -240
The problem is that we don't want to use the current setting of Daylight Savings or not.
We want use if daylight savings was in effect *at the date* being supplied.
And we can't even use the current rules:
- Second Sunday in March: spring forward (e.g. 3/14/2021 2:00 AM)
- First Sunday in November: fall back (e.g. 11/7/2021 2:00 AM)
because those are the rules today.
We need to use the rules that were in effect of the date we are considering.
- e.g. the rules changed in 2007. If we have an OrderDate from 2006, we need those older rules.
Also notice that some dates have two answers:
11/7/2021 1:45 AM: EDT (-4 hours)
11/7/2021 1:45 AM: EST (-5 hours, because at 2am we fallback to 1am, and encounter 1:45AM again, but this time as Standard time)
So which one do we return? Whatever one i feel like. That's the price you pay for not using UTC or datetime's with an offset.
*/
//Convert the date to a SYSTEM_TIME structure so we can call the Win32 API
SYSTEM_TIME stLocal;
DateTimeToSystemTime(LocalDateTime, out stLocal);
SYSTEM_TIME stUtc;
if (!TzSpecificLocalTimeToSystemTime(null, stLocal, out stUtc))
RaiseLastWin32Error();
//We now have both "local" and "utc" as a SYSTEM_TIME.
//Convert both to FILETIME so we can subtract them.
FILETIME ftLocal, ftUtc;
if (!SystemTimeToFileTime(stLocal, out ftLocal))
RaiseLastWin32Error();
if (!SystemTimeToFileTime(stUtc, out ftUtc))
RaiseLastWin32Error();
//Convert the FILETIMEs into Int64s.
//We do this because, as you know, you cannot access FILE_TIME structure
//as an 64-bit integer, even though it is two 32-bit integers back to back.
LARGE_INTEGER ulLocal, ulUtc;
ulLocal.LowPart = ftLocal.dwLowDateTime;
ulLocal.HighPart = ftLocal.dwHighDatetime;
ulUtc.LowPart = ftUtc.dwLowDateTime;
ulUtc.HighPart = ftUtc.dwHighDatetime;
//Now subtract the quadparts
Int64 delta = ulLocal.QuadPart - ulUtc.QuadPart;
//That delta is in 100ns intervals (0.00001 sec). We want it in whole minutes;
// 100 ns
// 0.1 us
// 0.0001 ms
// 0.0000001 s
delta = delta div 10000000; //100 ns ==> seconds (div is integer division)
delta = delta div 60; //seconds ==> minutes
return delta;
}
And then, of course, no function is complete without test cases
//After the Daylight Savings rule change of of 2007
Test("2019-01-21T09:00:00", -300); // (-5 hours) |
Test("2019-02-21T09:00:00", -300); // (-5 hours) |
Test("2019-03-21T09:00:00", -240); // (-4 hours) | Daylight savings
Test("2019-04-21T09:00:00", -240); // (-4 hours) | Daylight savings
Test("2019-05-21T09:00:00", -240); // (-4 hours) | Daylight savings
Test("2019-06-21T09:00:00", -240); // (-4 hours) | Daylight savings
Test("2019-07-21T09:00:00", -240); // (-4 hours) | Daylight savings
Test("2019-08-21T09:00:00", -240); // (-4 hours) | Daylight savings
Test("2019-09-21T09:00:00", -240); // (-4 hours) | Daylight savings
Test("2019-10-21T09:00:00", -240); // (-4 hours) | Daylight savings
Test("2019-11-21T09:00:00", -300); // (-5 hours) |
Test("2019-12-21T09:00:00", -300); // (-5 hours) |
//Before the Daylight Savings rule change of 2007
Test("2006-01-21T09:00:00", -300); // (-5 hours) |
Test("2006-02-21T09:00:00", -300); // (-5 hours) |
Test("2006-03-21T09:00:00", -300); // (-5 hours) | What what?
Test("2006-04-21T09:00:00", -240); // (-4 hours) | Daylight savings
Test("2006-05-21T09:00:00", -240); // (-4 hours) | Daylight savings
Test("2006-06-21T09:00:00", -240); // (-4 hours) | Daylight savings
Test("2006-07-21T09:00:00", -240); // (-4 hours) | Daylight savings
Test("2006-08-21T09:00:00", -240); // (-4 hours) | Daylight savings
Test("2006-09-21T09:00:00", -240); // (-4 hours) | Daylight savings
Test("2006-10-21T09:00:00", -240); // (-4 hours) | Daylight savings
Test("2006-11-21T09:00:00", -300); // (-5 hours) |
Test("2006-12-21T09:00:00", -300); // (-5 hours) |
//Testing spring-forward. Spring forward March 14, 2021 at 2:00 AM
//The weirdness here is that the time from 2:00:00..2:59:59 doesn't exist.
Test("2021-03-14T00:00:00", -300); // EST
Test("2021-03-14T00:59:59", -300); // EST
Test("2021-03-14T01:00:00", -300); // EST
Test("2021-03-14T01:59:00", -300); // EST
Test("2021-03-14T02:00:00", -240); // There is no March 14, 2021 2am - it doesn't exist. The clock goes from 1:59:59 am --> 3:00:00 am. The function does return 240. TODO: figure out why it returns 240
Test("2021-03-14T02:59:59", -240); // There is no March 14, 2021 2:59am - it doesn't exist.
Test("2021-03-14T03:00:00", -240); // EDT
//Testing fall-back. Fall back March 14, 2021 at 2:00 AM
//The weirdness here is that 1:30 AM exists twice.
//12:00 AM -> 12:59:59 AM -> [1:00 AM -> 1:59:59 AM --> 1:00 AM -> 1:59:59 AM] -> 2:00 AM
//So there's no way to know if 11/7/2021 1:30 AM was EDT or EST - both are correct, because it actually did happen twice.
Test("2021-11-07T00:00:00", -240); // EDT
Test("2021-11-07T00:59:59", -240); // EDT
Test("2021-11-07T01:00:00", -240); // EDT (and EST!)
Test("2021-11-07T01:59:59", -240); // EDT (and EST!)
//Test("2021-11-07T01:00:00", -300); // EST (and EDT!)
//Test("2021-11-07T01:59:59", -300); // EST (and EDT!)
Test("2021-11-07T02:00:00", -300); // EST

Related

time calculation between two date time based on shop opening and closing time

me has a table in oracle which TEMPhas shop open & Close time.
| COMPANY_ID | DAY_OF_WEEK | SHOP OPEN TIME | SHOP CLOSE TIME |
|------------|-------------|---------------------|---------------------|
| shop 1 | 1 | +00 10:00:00.000000 | +00 21:30:00.000000 |
| shop 1 | 2 | +00 10:00:00.000000 | +00 21:30:00.000000 |
| shop 1 | 3 | +00 10:00:00.000000 | +00 21:30:00.000000 |
| shop 1 | 4 | +00 10:00:00.000000 | +00 21:30:00.000000 |
| shop 1 | 5 | +00 10:00:00.000000 | +00 21:30:00.000000 |
| shop 1 | 6 | +00 10:00:00.000000 | +00 21:30:00.000000 |
| shop 1 | 7 | +00 11:00:00.000000 | +00 18:00:00.000000 |
| shop 2 | 1 | +00 10:30:00.000000 | +00 20:00:00.000000 |
| shop 2 | 2 | +00 09:30:00.000000 | +00 22:00:00.000000 |
| shop 2 | 3 | +00 09:30:00.000000 | +00 22:00:00.000000 |
| shop 2 | 4 | +00 09:30:00.000000 | +00 22:00:00.000000 |
| shop 2 | 5 | +00 11:00:00.000000 | +00 18:00:00.000000 |
| shop 2 | 6 | +00 09:30:00.000000 | +00 22:00:00.000000 |
| shop 2 | 7 | +00 09:00:00.000000 | +00 22:00:00.000000 |
Day-1 is saturday
me has another table for complaint, when customer complain TEMPthan we resolve teh query and calculate how much time we took to resolve. We don't take time in teh consideration if teh shop is close at that time. So if shop is open on Monday 09:00 to 22:00 TEMPthan night 22:00 to morning 09:00 time won't be considered .
complain table:
| SHOP | COMPLAIN NUMBER | COMPLAIN DAY TIME | RESOLVE DAY TIME | TIME TAKEN TO RESOLVE in minutes |
|-------|-------------------|---------------------|-------------------|-----------------------------------|
| SHOP1 | 1 | 01/10/2022 08:20 | 01/10/2022 16:10 | 310 |
| SHOP1 | 2 | 01/10/2022 08:20 | 06/10/2022 09:50 |
me have calculated manually for complaint number 1, time taken to resolve teh query is 310 mins.
01/10/2022 was Saturday and shop opening time was 11:00 AM based on shop open and close time time taken to resolve teh complaint is 5 hours 10 mins which 310 mins,
if dis day would be Monday and as we see opening time on Monday is 10AM TEMPthan time taken to resolve would be 370 mins. (open and closing time can be different for different shop for different day)
In dis example complaint and problem is for same day, so dis is bit easier but
If teh complaint stays for 4 or 5 days. How we should calculate as every day shop opening and closing time are different. So in teh second case time taken should be 4550 mins
01/10-570 complaint open for all day as complaint logged before shop opened ()
02/10-750 complaint open for all day
03/10-750 complaint open for all day
04/10-750 complaint open for all day
05/10-420 complaint open for all day
06/10-740 complaint close 10 mins before shop closing
Total is 3980 mins, Please halp
This question is currently in our queue. You'll get an email notification when we've added an answer
To get the overlaps with the shop opening times, you could use a hierarchical query or recursive CTE to split each complaint into its separate days, and calculate the equivalent day number (which seems to be 1 for Sunday through to 6 for Saturday), something like:
with rcte (shop, complain_number, complain_day_time, resolve_day_time,
active_day, active_day_of_week) as (
select shop, complain_number, complain_day_time, resolve_day_time,
trunc(complain_day_time), trunc(complain_day_time + 1) - trunc(complain_day_time + 1, 'IW') + 1
from complaints
union all
select shop, complain_number, complain_day_time, resolve_day_time,
active_day + 1, trunc(active_day + 2) - trunc(active_day + 2, 'IW') + 1
from rcte
where active_day < trunc(resolve_day_time)
)
select * from rcte
order by shop, complain_number, active_day
SHOP
COMPLAIN_NUMBER
COMPLAIN_DAY_TIME
RESOLVE_DAY_TIME
ACTIVE_DAY
ACTIVE_DAY_OF_WEEK
shop 1
1
2022-10-01 08:20:00
2022-10-01 16:10:00
2022-10-01 00:00:00
7
shop 1
2
2022-10-01 08:20:00
2022-10-06 21:20:00
2022-10-01 00:00:00
7
shop 1
2
2022-10-01 08:20:00
2022-10-06 21:20:00
2022-10-02 00:00:00
1
shop 1
2
2022-10-01 08:20:00
2022-10-06 21:20:00
2022-10-03 00:00:00
2
shop 1
2
2022-10-01 08:20:00
2022-10-06 21:20:00
2022-10-04 00:00:00
3
shop 1
2
2022-10-01 08:20:00
2022-10-06 21:20:00
2022-10-05 00:00:00
4
shop 1
2
2022-10-01 08:20:00
2022-10-06 21:20:00
2022-10-06 00:00:00
5
Then join each of those days to the shop times on that day, and use least/greatest to figure out how much of that day's hours to include, subtracting the active end/start times and multiplying the resulting number of days by 1440 to get it in minutes; and then sum up all of those for each complaint:
with rcte (shop, complain_number, complain_day_time, resolve_day_time,
active_day, active_day_of_week) as (
select shop, complain_number, complain_day_time, resolve_day_time,
trunc(complain_day_time), trunc(complain_day_time + 1) - trunc(complain_day_time + 1, 'IW') + 1
from complaints
union all
select shop, complain_number, complain_day_time, resolve_day_time,
active_day + 1, trunc(active_day + 2) - trunc(active_day + 2, 'IW') + 1
from rcte
where active_day < trunc(resolve_day_time)
)
select c.shop, c.complain_number, c.complain_day_time, c.resolve_day_time,
sum(round(1440 * (least(c.active_day + s.shop_close_time, c.resolve_day_time)
- greatest(c.active_day + s.shop_open_time, c.complain_day_time)))) as active_mins
from rcte c
join shops s on s.company_id = c.shop
and s.day_of_week = c.active_day_of_week
group by c.shop, c.complain_number, c.complain_day_time, c.resolve_day_time
order by c.shop, c.complain_number
SHOP
COMPLAIN_NUMBER
COMPLAIN_DAY_TIME
RESOLVE_DAY_TIME
ACTIVE_MINS
shop 1
1
2022-10-01 08:20:00
2022-10-01 16:10:00
310
shop 1
2
2022-10-01 08:20:00
2022-10-06 21:20:00
3860
fiddle showing the intermediate calculation as well.
I've adjusted the second complaint's resolve time to 21:20 because that shop is only open until 21:30 and you said "complaint close 10 mins before shop closing". That gets a total of 3860 minutes for that complaint - you seem to have added an extra day to your calculation to get 4550.

Oracle Date Field is not sorting correctly

I have a column in oracle, the column type is "DATE", I am 100% sure of this. However when I run the query, it is not producing the correct result. I cannot for the life of me find anything different about the dates that are not working.
I'm looking for any suggestions on hidden oracle setting that might indicate a difference between these rows that I cannot see here.
Thanks
SELECT DISTINCT DATE FROM DATE_TABLE ORDER BY DATE;
DATE |
--------------------|
2017-02-19 00:00:00 |
2017-02-26 00:00:00 |
2017-03-19 01:00:00 |
2017-03-26 01:00:00 |
2017-03-05 00:00:00 |
2017-03-12 00:00:00 |
2017-03-19 01:00:00 |-2017-03-19 01:00:00 |Typ=12 Len=7: 50,53,3,13,2,1,1 |
2017-03-19 01:00:00 |-2017-03-19 01:00:00 |Typ=12 Len=7: 50,53,3,13,2,1,1 |
2017-03-19 01:00:00 |-2017-03-19 01:00:00 |Typ=12 Len=7: 50,53,3,13,2,1,1 |
2017-03-19 01:00:00 |-2017-03-19 01:00:00 |Typ=12 Len=7: 50,53,3,13,2,1,1 |
2017-03-05 00:00:00 | 2017-03-05 00:00:00 |Typ=12 Len=7: 78,75,3,5,1,1,1 |
2017-03-05 00:00:00 | 2017-03-05 00:00:00 |Typ=12 Len=7: 78,75,3,5,1,1,1 |
2017-03-05 00:00:00 | 2017-03-05 00:00:00 |Typ=12 Len=7: 78,75,3,5,1,1,1 |
2017-03-05 00:00:00 | 2017-03-05 00:00:00 |Typ=12 Len=7: 78,75,3,5,1,1,1 |
2017-03-12 00:00:00 | 2017-03-12 00:00:00 |Typ=12 Len=7: 78,75,3,c,1,1,1 |
2017-03-12 00:00:00 | 2017-03-12 00:00:00 |Typ=12 Len=7: 78,75,3,c,1,1,1 |
2017-03-12 00:00:00 | 2017-03-12 00:00:00 |Typ=12 Len=7: 78,75,3,c,1,1,1 |
2017-03-12 00:00:00 | 2017-03-12 00:00:00 |Typ=12 Len=7: 78,75,3,c,1,1,1 |
2017-03-26 00:00:00 | 2017-03-26 00:00:00 |Typ=12 Len=7: 78,75,3,1a,1,1,1 |
2017-03-26 00:00:00 | 2017-03-26 00:00:00 |Typ=12 Len=7: 78,75,3,1a,1,1,1 |

Algorithm to calculate automatic adjusted statements according to payment amount

Background:
I decided to make a plan to save let´s say 1200 Euros in 6 months.
The problem is that I could not say that I will save 200 per month because sometimes I have to spend more and sometimes I might have a bonus or something.
For example, in the first month I could save only 100 Euros. Thus, I would like to split the remaining 100 in the other 5 remaining months: 20 euros more each month.
Original plan:
Jan | Feb | Mar | Apr | May | Jun
200 | 200 | 200 | 200 | 200 | 200 -> Total is 1200
Actual plan for the first month
Jan | Feb | Mar | Apr | May | Jun
100 | 220 | 220 | 220 | 220 | 220 -> Total is still 1200
Then, on February I got my bonus and could save 300 instead of 220. So now I will divide the extra 80 bucks in the remaining 4 months. Since it was more than I should have saved, now I will subtract. 80/4 = 20
Actual for the second month:
Jan | Feb | Mar | Apr | May | Jun
100 | 300 | 200 | 200 | 200 | 200 -> Total is still 1200
Question: What would be the algorithm to automatically adjust the value to be saved for the remaining installments according to the i (month in question), goal (final amount, constant) and amount already deposited?
Is it possible to represent this 3 parameters in a function?
Thank you
It is actually not an algorithm, it is simple math. Assume that you are on month i(a value from 1 to 6) and so far(for months 1, 2... i-1) you've saved X dollars. Then for the remaining months, you need to save (1200 - X) / (6 - i + 1). I divide by (6 - i + 1) because this is the number of months from i-th inclusive.

List all days between two dates in Oracle

I am converting a postgres app to an Oracle app.
I came across this query:
WITH cost AS (SELECT
well_schedules.id,
generate_series(well_schedules.start_date::timestamp, well_schedules.end_date, '1 Day') AS "Date",
(well_schedules.drilling_engineering_estimate * well_schedules.well_estimated_working_interest)/((well_schedules.end_date - well_schedules.start_date) + 1) AS "Cost Per Day"
FROM
well_schedules
)
SELECT date_trunc('quarter', "Date"), COUNT("Cost Per Day"), id
FROM cost
GROUP BY id, date_trunc('quarter', "Date")
ORDER BY date_trunc('quarter', "Date")
The part I am struggling with is the generate_series line.
That line takes a start_date and end_date and lists all days between those two dates. We need that information to compile per day/week/month/quarter/year reports (or at least we assume we need that info).
Our data looks like this:
well_schedules
| id | start_date | end_date | cost |
| 1 | '2015-01-01' | '2015-03-20' | 100 |
We assume cost_per_day is equal across all days, so we'd like to generate a report that lets us look at cost_per_day, cost_per_week, cost_per_month, cost_per_year, and cost_per_quarter. cost_per_week/month/quarter/year is calculated by grouping the days by week/month/quarter/year and summing the associated cost_per_days
SQL Fiddle
Oracle 11g R2 Schema Setup:
CREATE TABLE well_schedules ( id, start_date, end_date, cost ) AS
SELECT 1 , DATE '2015-01-01', DATE '2015-01-20', 100 FROM DUAL;
Query 1:
SELECT ID,
COLUMN_VALUE AS Day,
COST / ( end_date - start_date + 1 ) AS Cost_per_day
FROM well_schedules,
TABLE (
CAST(
MULTISET(
SELECT start_date + LEVEL - 1
FROM DUAL
CONNECT BY start_date + LEVEL - 1 <= end_date
)
AS SYS.ODCIDATELIST
)
)
Results:
| ID | DAY | COST_PER_DAY |
|----|---------------------------|--------------|
| 1 | January, 01 2015 00:00:00 | 5 |
| 1 | January, 02 2015 00:00:00 | 5 |
| 1 | January, 03 2015 00:00:00 | 5 |
| 1 | January, 04 2015 00:00:00 | 5 |
| 1 | January, 05 2015 00:00:00 | 5 |
| 1 | January, 06 2015 00:00:00 | 5 |
| 1 | January, 07 2015 00:00:00 | 5 |
| 1 | January, 08 2015 00:00:00 | 5 |
| 1 | January, 09 2015 00:00:00 | 5 |
| 1 | January, 10 2015 00:00:00 | 5 |
| 1 | January, 11 2015 00:00:00 | 5 |
| 1 | January, 12 2015 00:00:00 | 5 |
| 1 | January, 13 2015 00:00:00 | 5 |
| 1 | January, 14 2015 00:00:00 | 5 |
| 1 | January, 15 2015 00:00:00 | 5 |
| 1 | January, 16 2015 00:00:00 | 5 |
| 1 | January, 17 2015 00:00:00 | 5 |
| 1 | January, 18 2015 00:00:00 | 5 |
| 1 | January, 19 2015 00:00:00 | 5 |
| 1 | January, 20 2015 00:00:00 | 5 |
I will suggest the code below that consider the first and last day of the month from two dates:
Example:
Date Initial: 01/10/2014
Date Final: 12/21/2018
The code will return:
01/01/2014
02/01/2014
03/01/2014
04/01/2014
...
12/28/2018
12/29/2018
12/30/2018
12/31/2018
The Code:
SELECT
CAL.DT AS "Date"
,TO_NUMBER(TO_CHAR(CAL.DT,'DD')) AS "Day"
,TO_NUMBER(TO_CHAR(CAL.DT,'MM')) AS "Month"
,TO_NUMBER(TO_CHAR(CAL.DT,'YY')) AS "YearYY"
,TO_NUMBER(TO_CHAR(CAL.DT,'YYYY')) AS "YearYYYY"
,TO_CHAR(CAL.DT,'day') AS "Description_Day"
,TO_CHAR(CAL.DT,'dy') AS "Description_Day_Abrev"
,TO_CHAR(CAL.DT,'Month') AS "Description_Month"
,TO_CHAR(CAL.DT,'Mon') AS "Description_Month_Abrev"
,TO_CHAR(CAL.DT,'dd month yyyy') AS "Date_Text"
FROM (
SELECT
(
TO_DATE(SEQ.MM || SEQ.YYYY, 'MM/YYYY')-1
) + SEQ.NUM AS "DT"
FROM
(
SELECT RESULT NUM,
TO_CHAR(( -- Minimum Date
TO_DATE('01/01/2014', 'DD/MM/YYYY')
) , 'MM') AS "MM",
TO_CHAR(( -- Minimum Date
TO_DATE('01/01/2014', 'DD/MM/YYYY')
) , 'YYYY') AS "YYYY"
FROM
(
SELECT ROWNUM RESULT FROM DUAL CONNECT BY LEVEL <= (
(
-- Maximum Date
LAST_DAY(TO_DATE('31/12/2018', 'DD/MM/YYYY')) -- Always Last Day
-
-- Maximum Date
TRUNC(TO_DATE('01/01/2014', 'DD/MM/YYYY')) -- Always First Day of Month
) + 1 -- Because the First Day (RESULT) don't begin at zero
)
) -- How many sequences (RESULT) to generate
) SEQ
) CAL
;

Cron job every day from 8AM to 8PM at 20 minutes interval

How to run cron job every day from 8:00 AM to 8:00 PM at 20 minutes interval eg cron job should start at 8:00 AM every day, then run at 8:20 AM then 8:40 AM then 9:00 AM up to 8:00 PM. Thanks.
EDIT: How to Implement it with ruby whenever gem.
Just use two cronjobs:
*/20 8-19 * * * /your/script
0 20 * * * /your/script
That is:
one to run every 20 minutes from 8 to 19 hours
one to run at 20.00.
As a reminder, this is the format for a cronjob:
+---------------- minute (0 - 59)
| +------------- hour (0 - 23)
| | +---------- day of month (1 - 31)
| | | +------- month (1 - 12)
| | | | +---- day of week (0 - 6) (Sunday=0 or 7)
| | | | |
* * * * * command to be executed

Resources