dateutil.relativedelta handles years incorrectly - python-dateutil

There's something wrong with adding years:
from datetime import datetime
from dateutil.relativedelta import relativedelta
if __name__ == '__main__':
date = datetime.today().date()
print(date)
print(date + relativedelta(year=1))
### 2022-07-27
### 0001-07-27 – why!?
Could anyone explain that?

The issue you are having is that year (singular) sets the year of whatever it is added to, whereas years (plural) represents an offset in years. See the documentation, which has a whole section on the difference.

Related

How to split Japanese Date which include month and year into or Date format [duplicate]

This question already has answers here:
How does Java "week year" really work?
(2 answers)
Why I get a wrong result when parsing a date from string with SimpleDateFormat ? (Java) [duplicate]
(1 answer)
java parsing string to date
(2 answers)
Is SimpleDateFormat in Java work incorrect or I did any mistake? See code sample [duplicate]
(2 answers)
Closed 2 years ago.
I want to split Japanese date which is in format "2020年7月" into separate array so that can get the year and month from that.
I tried SimpleDateFormatter to format Japanese date with and have the year and date separated with "/"but the output is wrong:
Tried this code:
val inputFormat = SimpleDateFormat("YYYY年M月")
val date = inputFormat.parse("2020年7月")
val outputText = SimpleDateFormat("YYYY/MM").format(date)
input :2020年7月
output:2020/12
Can anyone help me in this?
You should be using java.time for this because the datetime classes from java.util are outdated (but still not deprecated).
The following example shows a way using a java.time.format.DateTimeFormatter for parsing a String formatted according to a certain pattern and a java.time.YearMonth, a class obviously designed for the purpose of creating a month in a year without respect to a day of month:
import java.time.YearMonth;
import java.time.format.DateTimeFormatter;
fun main() {
val jpYearMonth = "2020年7月"
val japaneseDtf = DateTimeFormatter.ofPattern("uuuu年M月")
val yearMonth = YearMonth.parse(jpYearMonth, japaneseDtf)
println(yearMonth.format(DateTimeFormatter.ofPattern("uuuu/MM")))
}
In order to achieve your desired output this code has to use a different DateTimeFormatter defining the output pattern because the default pattern (internal use when you just println(yearMonth)) would be hyphon-separated (2020-07):
2020/07

Exact 1 year previous date in Scala

I have a date string like this - 190515(YYMMDD) format. How to get a populate a exact one year previous date from this? ie, Expected Answer - 180515 (YYMMDD). I am using Scala for this.
I have tried the below. But am getting the below exception - Text '190515' could not be parsed
import java.time.LocalDateTime
import java.time.format.{ DateTimeFormatter, DateTimeParseException }
val d1 =LocalDateTime.parse("190515",DateTimeFormatter.ofPattern("yyMMdd"))
d1.minusYears(1)
LocalDateTime is used for points of time having both a date and a time precision. Yours only have a date, so you should be using LocalDate

Same unixtime yields different date time in joda than the correct date time

I read from a very old post here on stackoverflow that joda is a possible solution to convert Unix timestamp.
import org.joda.time._
new DateTime(1511544070).toString("yyyy-MM-dd")
I got 1970-01-18 for this case, however, this is wrong because the date should be
according to this online converter: 11/24/2017 # 5:21pm (UTC)
It is possible the online converter is correct because the sample unix timestamp 1511544070 is from a dataset that date range is November 25 to December 03, 2017, the dataset is from China time which is 8 hours ahead of UTC, meaning 11/24/2017 # 5:21pm (UTC) is actually 11/25/2017 # 1:21am (Beijing Time)
Where can I get a working library or is there a working library that can get the same result like the online converter?
You can do that using java.time:
import java.time.{ LocalDateTime, ZoneOffset }
import java.time.format.DateTimeFormatter
LocalDateTime.ofEpochSecond(1511544070, 0, ZoneOffset.UTC)
.format(DateTimeFormatter.ofPattern("yyyy-MM-dd # h:mm a"))
Looking at the documentation for joda-time we see that a DateTime can take a Long specifying the milliseconds since 1 Jan 1970. However, you seem to be providing a value in seconds. Joda-time is actually calculating it correctly, since since 1511544070/(1000*3600*24) equals 17.49 days, i.e. 1970-01-18.
To get the expected result multiply with 1000:
new DateTime(1511544070*1000).toString("yyyy-MM-dd")
To get the time in another timezone, add withZone() as follows (for Shanghai/Beijing):
new DateTime(1511544070*1000).toString("yyyy-MM-dd")
.withZone(DateTimeZone.forID("Asia/Shanghai"))

Python dateutil - bug with choosing closest day with BYMONTHDAY

I am using python's dateutil module to parse recurring rules in my calendar. A problem arises with the following rrule:
from dateutil.rrule import rrulestr
def test():
rrule = 'FREQ=MONTHLY;INTERVAL=1;BYMONTHDAY=30;UNTIL=20180331T2359'
dtstart = datetime.datetime(2018, 1, 1, 18, 0)
dates = list(rrulestr(rrule + ';UNTIL=', dtstart = dtstart ))
This results in the following output (missing February):
datetime: 2018-01-30 18:00:00
datetime: 2018-03-30 18:00:00
Is this a bug in dateutil module and how should I fix it? Or am I doing something wrong?
Per my answer on this equivalent question, this is a deliberate feature of the iCalendar RFC that dateutil is implementing, because dateutil implements RFC 2445 and does not support all (or most) of the features of the updated RFC 5545. The relevant section of RFC 2445:
Recurrence rules may generate recurrence instances with an invalid date (e.g., February 30) or nonexistent local time (e.g., 1:30 AM on a day where the local time is moved forward by an hour at 1:00 AM). Such recurrence instances MUST be ignored and MUST NOT be counted as part of the recurrence set.
February is missing because 2018-02-30 is an invalid date (it's actually the example specified in the RFC).
One thing to note is that this pull request implements the functionality you want, but it is (as of this writing) currently blocked waiting for support of SKIP in BYWEEKNO. After that is merged, you will be able to modify your RRULE:
rrule = ('FREQ=MONTHLY;INTERVAL=1;BYMONTHDAY=30;UNTIL=20180331T2359;'+
'SKIP=BACKWARD;RSCALE=GREGORIAN')
Until then, your best option may be to use a BYMONTHDAY=28 and then add a relativedelta(day=30) to the result, e.g.:
from dateutil.rrule import rrule, MONTHLY
from dateutil.relativedelta import relativedelta
def end_of_month(dtstart, until):
rr = rrule(freq=MONTHLY, interval=1, bymonthday=28,
dtstart=dtstart, until=until)
for dt in rr:
yield dt + relativedelta(day=30)
This works because the 28th exists in all months (so the rrule will always generate it) and relativedelta has the "fall backwards at end of month" behavior that you are looking for. To be 100% safe, you can choose bymonthday=1 instead, it is equivalent in this case.

Joda-Time : Date calculation

I would like to calculate precisely the months between two dates to achieve this I do something like :
DateTimeZone ZONE = DateTimeZone.forID("Europe/London");
String DATE_FORMAT = "dd/MM/yyyy";
DateTimeFormatter FORMATTER = DateTimeFormat.forPattern(DATE_FORMAT).withZone(ZONE);
LocalDate dateTime = FORMATTER.parseLocalDate("28/05/2013");
LocalDate dateTime6MonthAfter = FORMATTER.parseLocalDate("28/02/2014");
Period todayUntilEndOfContract = new Period(dateTime,dateTime6MonthAfter);
todayUntilEndOfContract.getMonths() +"M/"+ todayUntilEndOfContract.getWeeks() +"W/"+ todayUntilEndOfContract.getDays() +"D/");
So this give me precisely 9 month between 28/05/2013 and 28/02/2014 BUT!!!
when I calculate the dates (29, 30, 31)/05/2013 with 28/02/2014 it always give me 9 month normally it should say 8M/3W/(6,5,4)D/ why is it always 9M/0W/0D please...?
Thanks a lot
Your issue is that you are expecting something a little different than what is provided. If I ask you the question "what is 30th January plus one month?" then there are a number of different answers which are valid under different assumptions. In Joda's case the answer is "28th February" (or 29th if a leap year).
Although you are asking for month-based information I would suggest that you obtain the number of days instead and use that as a basis, as it is probably closer to what you need:
int days = Days.daysBetween(dateTime, dateTime6MonthAfter).getDays();
You can always use this number to feed back in to your code and obtain different values to fit your requirements.