Reputation: 540
I want to get the set of years which pertain to a specific date, week of the day and month. There are possibilities that I can get various years from this pattern. Suppose Date is 15, Month is August and Week of the day is Tuesday then, How would I find the years that are valid? Is there a formula for this?
Upvotes: 8
Views: 2485
Reputation: 20984
To solve it in Python I use the rrule module, part of the dateutil module.
I assume you are looking for years between this year (2024) and the year 1900.
In the example:
freq=YEARLY
because there is at most one date per yearbyweekday=TU
for your "day of the week is Tuesday"bymonthday=15
for your "date is 15"bymonth=8
for your "month is August" (January is 1, December is 12)dtstart=date(year=1900, month=1, day=1)
for my early limit year 1900until=date(year=2024, month=12, day=31)
for my late limit year 2024from datetime import date
from dateutil.rrule import rrule, YEARLY, TU
rule=rrule(
freq=YEARLY,
byweekday=TU,
bymonthday=15,
bymonth=8,
dtstart=date(year=1900, month=1, day=1),
until=date(year=2024, month=12, day=31),
)
print(*[date.year for date in rule], sep=", ")
Answer: 1905, 1911, 1916, 1922, 1933, 1939, 1944, 1950, 1961, 1967, 1972, 1978, 1989, 1995, 2000, 2006, 2017, 2023
.
Use an iCalendar recurrence rule to solve the problem in any programming language that has a recurrence rule resolver package.
The iCalendar standard is a data format for representing and exchanging calendaring and scheduling information. The Internet Engineering Task Force maintains the standard in a document called RFC5545, and it has a Wikipedia page.
The recurrence rule expression for my interpretation of your problem is:
DTSTART:19000101T000000Z
RRULE:FREQ=YEARLY;UNTIL=20241231T000000Z;BYDAY=TU;BYMONTH=8;BYMONTHDAY=15
Edouard Courty's article "The best way to programmatically handle recurrence" recommends more libraries for popular programming languages:
Some web applications let you check the answers from your own code because they answer the question for all dates.
Use the 10000 year calendar website to identify all years that match the specified day, day of the week, and month.
Use the rrule.js demo to tabulate answers, generate iCalendar recurrence rule syntax, and generate code for Jakub Roztocil's rrule JavaScript library.
Use David Bal's RRULE Recurrence Calculator to tabulate recurrence rule expressions.
I credit the 10000-year-calendar discovery to users こもりのり and V. Atkin. Their answers got deleted because they shared no code.
Upvotes: 0
Reputation: 26
Here is a way in Java 8 using the LocalDate parser to do the work for you. I used a modified version of this when I had a bunch of dates that had no year but were either the current year or the next one.
String dateString = "Mon Dec 23";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("E MMM d yyyy");
Integer startYear = 2000;
Integer endYear = 3000;
List<Integer> validYears = new ArrayList<>();
for(int i = startYear; i <= endYear; i++){
try{
LocalDate localDate = LocalDate.parse(dateString + " " + i, formatter);
validYears.add(localDate.getYear());
} catch (Exception e){
//Years that are not valid
}
}
for(Integer year: validYears){
System.out.println(year);
}
Upvotes: 0
Reputation: 2164
Would this fully solve your problem?
The idea behind this:
(till your specified MAX_DATE is reached)
List<Integer> validYears = new ArrayList<>();
LocalDate date = LocalDate.of(0, Month.AUGUST, 15);
while (date.getYear() < 2015) {
if (date.getDayOfWeek() == DayOfWeek.TUESDAY) {
validYears.add(date.getYear());
}
date = date.plusYears(1);
}
validYears.forEach(year -> System.out.println(year));
Edit: if your date is February 29th you should add following code (Because if you add 1 year to 0000-02-29 it will give you 0001-02-28, and from there on you will stay at the 28th)
if (date.isLeapYear()) { //And date was feb. 29
date = date.withDayOfMonth(29);
}
Heres a version with streams:
int day = 29;
Month month = Month.FEBRUARY;
List<LocalDate> collect = IntStream.range(0, 2016).filter(year -> day <= LocalDate.of(year, month, 1).lengthOfMonth())
.mapToObj(year -> LocalDate.of(year, month, day)).filter(date -> date.getDayOfWeek() == DayOfWeek.TUESDAY)
.collect(Collectors.toList());
collect.forEach((year -> System.out.println(year)));
Upvotes: 4
Reputation: 77
This question relates to the classical Dommsday algo.
A simple method to calculate is Kraitchik's method.
Kraitchik method -
w = d + m + c + y mod 7,
where w is the day of the week (counting upwards from 1 on Sunday instead of 0 in Gauss's version);
and d, m, c and y are numbers depending on the day, month, and year as in the following tables:
Month 1 2 3 4 5 6 7 8 9 10 11 12
m 1 4 3 6 1 4 6 2 5 0 3 5
For the Gregorian calendar, take the century of the year (ex, the year 1986 would be 1900, 2014 would be 2000).
[Century/100] mod 4: 0 1 2 3
c: 0 5 3 1
For the Julian calendar,
[Century/100] mod 7: 0 1 2 3 4 5 6
c: 5 4 3 2 1 0 6
Finally, the year number is obtained from this table (with 1 being subtracted from dates in January or February):
Last two digits of the year y
00 06 17 23 28 34 45 51 56 62 73 79 84 90 0
01 07 12 18 29 35 40 46 57 63 68 74 85 91 96 1
02 13 19 24 30 41 47 52 58 69 75 80 86 97 2
03 08 14 25 31 36 42 53 59 64 70 81 87 92 98 3
09 15 20 26 37 43 48 54 65 71 76 82 93 99 4
04 10 21 27 32 38 49 55 60 66 77 83 88 94 5
05 11 16 22 33 39 44 50 61 67 72 78 89 95 6
That's it. You may obtain more background detailed info from wikipedia
Upvotes: 1
Reputation: 373
Here is a simple formula you can do even in your head.You can find more info here: How to determine the day of the week, given the month, day and year
Upvotes: 1