Applescript: Addition of months via adding multiples of days with strange behaviour - date

So I am trying to define a function that adds months. But already in the beginning, I stumble on the following issue.
set testdate to (current date)
set the month of testdate to (1 as integer)
set the day of testdate to (1 as integer)
tell testdate to set {day} to {day + 32 * 4}
testdate
I would expect to get at least an output of a date in May 2020 (of course not first of May, but something in the beginning), however, the output is
date "Montag, 26. August 2019 um 15:53:13"
instead. Can someone explain to me, please?
If I change, for instance, the "4" above into a "3", then I get the expected
date "Montag, 6. April 2020 um 16:06:21"
With the help of red_menace, I was able to implement the following procedure that adds months.
on addMonths onto oldDate by m
copy oldDate to newDate
set newDate to newDate + (days * 31 * m)
if newDate's day is not oldDate's day then set newDate to (newDate) - ((newDate's day) - (oldDate's day)) * days
return newDate
end addMonths
(However, an explanation of why this bug happens is still not there.)

I don't think it is a bug so much as it just may be a result of the way the date object is implemented internally (my guess for that is that 127 works, but 128 does not). The day property is for the day of the month (1 - 31), so cheating a little by using out of bounds days might work for overflowing a few days into nearby months, but they probably didn't bother checking for something exceeding the size of the allotted structure.
When manipulating dates, the normal procedure for a time difference is to add or subtract the number of seconds. The date class has various properties such as day and month, but there are also constants such as days or hours, which contain the number of seconds in a day or hour, respectively (they only go to weeks, since months do not have a fixed number of days):
set testdate to (current date) -- get a date object
set the month of testdate to 1 -- set new month
set the day of testdate to 1 -- set new day
log 24 * hours
log days
return testdate + (days * 32 * 4) -- add to the date
See the date class reference in the AppleScript Language Guide.

Related

MS Access / forcing a date range 2 months back, bound to this week

I have a query where I need, as date criteria, the week ending two months prior.
So for example if I ran the query on Monday (as of right now, the last Monday was 2/1/2016), it would look at 11/29/2015 through 12/5/2015 inclusive (Sunday through Saturday).
And then next week if I ran it, it would focus on 12/6/2015 through 12/12/2015 (Sunday through Saturday).
However I need it to return this exact same date range no matter which weekday of the week I run it. So for example the date range 11/29/2015 through 12/5/2015 would be selected if I ran it on 2/1/2016 through 2/5/2016 (Mon-Fri).
I'm not sure what the best way is to go about this. I've considered somehow trying to find the next Saturday and then clocking that back a few weeks, but there doesn't seem to be a week option in dateadd().
To get the first weekday of a week from Sunday to Saturday:
FirstWeekDate = DateAdd("d", 1 - Weekday(Date()), Date())
To go back, say 8 weeks:
EightWeeksBack = DateAdd("ww", -8, FirstWeekDate)
Then you can just add/subtrack days to get your intervals, for example.
EightWeeksBackLast = DateAdd("d", 6, DateAdd("ww", -8, FirstWeekDate))

How to get total experience in terms of date object

I have a condition here in which I will have total experience in terms of month and year. For example, two drop down will be there for asking total number of experience in month and year. So if I am working from 1 Jan 2012, then I will write total experience as 3 year and 11 months. Now I have to convert this 3 year and 11 months into date format so that I can save this into database
You could use java.util.Calendar:
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.MONTH, month);
calendar.add(Calendar.YEAR, year);
Date date = calendar.getTime();
As a word of caution, the day field would be set to today's date. Check the intended behaviour if the current day is outside of the bounds for the target month. For example, setting the month to February when calendar has a day field of 30. It might be wise to set the day to a known, valid value for every month (eg: 1) before setting the month and year.
Use DATE_SUB() function:
Try this:
SELECT DATE_SUB(DATE_SUB(CURRENT_DATE(), INTERVAL 3 YEAR), INTERVAL 11 MONTH);
You can use mysql's date_sub() function or <date> - interval <expression> unit syntax to subtract an interval from a date.
select date_sub(curdate(),interval '3-11' YEAR_MONTH) as start_date
UPDATE:
Following the conversation between the OP and #eggyal, the OP need to replace the period in the incoming data with - and construct an insert statement as follows:
insert into mytable (...,join_date,...) values (...,date_sub(curdate(),interval '3-11' YEAR_MONTH),...)

Filtering for dates less than or or equal to 9 months in the future in an Access query

Once a week I need to run a report where I query an Access database for any product that will expire in 9 months or less. The way they want it calculated is to take the date 9 months into the future and return anything that expires at the end of that month or sooner. If it were simply 270 days or less, I'd have no problem. (I'd also have no problem if I could do it in Excel, but that's not an option for now).
I came up with a solution that works every month of the year, unless it happens to be March (more specifically between March 6th and April 5th).
< DateValue(Month(Date()+270)+1 & "/1/" & Year(Date()+270))
So basically I'm:
adding 270 days to today's date
extracting the resulting month
adding 1 to the month
putting it back together as a text string so I can use < the 1st of the following month
for the year, I'm using the year from the date +270 days so I don't end up using the current year by accident
The trouble is that for the date range above (which I unhappily discovered today), I land in December when I add 270 days, so the following month is in a different year. As a result, my report only produced items that already expired.
In other words, on March 5th, I would have needed a list of everything expiring prior to December 1, but on March 6th, I need everything before January 1 of the next year.
Is there a more effective way to do this that avoids this issue? I thought of using
You may have had DateDiff in mind, and it can be used:
Where DateDiff("m", Date(), [YourDateField]) Between 0 And 9
However, that will ignore an index you might have on [YourDateField].
This, however, will include products that expired previously in the current month.
The alternative is DateSerial as Hans showed but he forgot that in SQL Date() must be used and that only those products that will expire should be listed:
Where [YourDateField] Between Date() And DateSerial(Year(Date()), Month(Date()) + 10, 0)
Use the DateSerial Function to compute the future date you need.
Here is a demonstration in the Access Immediate window which computes the date 9 months from today:
? Date
3/6/2015
? DateSerial(Year(Date), Month(Date) + 9, Day(Date))
12/6/2015
However, as I understand your requirement, you actually want dates from that entire month. In that case you can compute the first of the month which is 10 months from today and ask for everything less than that date.
? DateSerial(Year(Date), Month(Date) + 10, 1)
1/1/2016
You can include that expression in your query like this ...
WHERE expire_date < DateSerial(Year(Date()), Month(Date()) + 10, 1)

how would I query 4/1/ of the 72nd birth date year > an input date

I have tried the following:
add_months(to_Date('04/01/ind.birth_dte','MM/DD/YYYY'), 864) >= to_date('&StartDt','MM/DD/YYYY')
Is there a better way to pull April first of the participant's 72nd birth date?
You could use an interval calculation instead, but not sure how you're defining 'better'. Assuming you do want April 1st of the year in which their 72 birthday falls:
trunc(ind.birth_dte, 'YYYY') + interval '72-3' year to month
The trunc() function goes to the first day of their birth year, and the interval adds 72 years and 3 months to that, which will be April 1st.
SQL Fiddle with some sample dates, including a leap day to show that isn't a problem.
Or to compare that adjusted date with a fixed date as a filter:
where trunc(ind.birth_dte, 'YYYY') + interval '72-3' year to month
> to_date('&StartDt','MM/DD/YYYY');
SQL Fiddle.
You can use the trunc() method with your version as well to save building up a string and calling to_date, adding an additional three months to the add_months call (though I'd suggest you at least need a comment indicating where '867' comes from):
where add_months(trunc(ind.birth_dte, 'YYYY'), 867)
> to_date('&StartDt','MM/DD/YYYY');

SQL DateDiff Weeks - Need and alternative

The MS SQL DateDiff function counts the number of boundaries crossed when calculating the difference between two dates.
Unfortunately for me, that's not what I'm after. For instance, 1 June 2012 -> 30 June 2012 crosses 4 boundaries, but covers 5 weeks.
Is there an alternative query that I can run which will give me the number of weeks that a month intersects?
UPDATE
To try and clarify exactly what I'm after:
For any given month I need the number of weeks that intersect with that month.
Also, for the suggestion of just taking the datediff and adding one, that won't work. For instance February 2010 only intersects with 4 weeks. And the DateDiff calls returns 4, meaning that simply adding 1 would leave me the wrong number of weeks.
Beware: Proper Week calculation is generally trickier than you think!
If you use Datepart(week, aDate) you make a lot of assumptions about the concept 'week'.
Does the week start on Sunday or Monday? How do you deal with the transition between week 1 and week 5x. The actual number of weeks in a year is different depending on which week calculation rule you use (first4dayweek, weekOfJan1 etc.)
if you simply want to deal with differences you could use
DATEDIFF('s', firstDateTime, secondDateTime) > (7 * 86400 * numberOfWeeks)
if the first dateTime is at 2011-01-01 15:43:22 then the difference is 5 weeks after 2011-02-05 15:43:22
EDIT: Actually, according to this post: Wrong week number using DATEPART in SQL Server
You can now use Datepart(isoww, aDate) to get ISO 8601 week number. I knew that week was broken but not that there was now a fix. Cool!
THIS WORKS if you are using monday as the first day of the week
set language = british
select datepart(ww, #endofMonthDate) -
datepart(ww, #startofMonthDate) + 1
Datepart is language sensistive. By setting language to british you make monday the first day of the week.
This returns the correct values for feburary 2010 and june 2012! (because of monday as opposed to sunday is the first day of the week).
It also seems to return correct number of weeks for january and december (regardless of year). The isoww parameter uses monday as the first day of the week, but it causes january to sometimes start in week 52/53 and december to sometimes end in week 1 (which would make your select statement more complex)
SET DATEFIRST is important when counting weeks. To check what you have you can use select ##datefirst. ##datefirst=7 means that first day of week is sunday.
set datefirst 7
declare #FromDate datetime = '20100201'
declare #ToDate datetime = '20100228'
select datepart(week, #ToDate) - datepart(week, #FromDate) + 1
Result is 5 because Sunday 28/2 - 2010 is the first day of the fifth week.
If you want to base your week calculations on first day of week is Monday you need to do this instead.
set datefirst 1
declare #FromDate datetime = '20100201'
declare #ToDate datetime = '20100228'
select datepart(week, #ToDate) - datepart(week, #FromDate) + 1
Result is 4.