summaryrefslogtreecommitdiff
path: root/src/iter/yearinfo.rs
diff options
context:
space:
mode:
authorFredrik Meringdal <fmeringdal@hotmail.com>2020-10-25 23:00:50 +0100
committerFredrik Meringdal <fmeringdal@hotmail.com>2020-10-25 23:00:50 +0100
commitdc44e5f2312bbb8ac411b9dc0b3b52eb3b351b6c (patch)
treeee75b9aeac7c4b18d21b5dd0cb37e9c2098cfc54 /src/iter/yearinfo.rs
parent55db5800701e9965b19ede01266442b11956b54b (diff)
downloadrust_rrule-dc44e5f2312bbb8ac411b9dc0b3b52eb3b351b6c.zip
restructure files
Diffstat (limited to 'src/iter/yearinfo.rs')
-rw-r--r--src/iter/yearinfo.rs217
1 files changed, 217 insertions, 0 deletions
diff --git a/src/iter/yearinfo.rs b/src/iter/yearinfo.rs
new file mode 100644
index 0000000..8a944f7
--- /dev/null
+++ b/src/iter/yearinfo.rs
@@ -0,0 +1,217 @@
+use crate::masks::MASKS;
+use crate::options::*;
+use chrono::prelude::*;
+use crate::datetime::to_ordinal;
+
+
+#[derive(Debug)]
+pub struct YearInfo {
+ pub yearlen: usize,
+ pub nextyearlen: usize,
+ pub yearordinal: isize,
+ pub yearweekday: usize,
+ pub mmask: Vec<usize>,
+ pub mrange: Vec<usize>,
+ pub mdaymask: Vec<isize>,
+ pub nmdaymask: Vec<isize>,
+ pub wdaymask: Vec<usize>,
+ pub wnomask: Option<Vec<usize>>,
+}
+
+fn is_leap_year(year: i32) -> bool {
+ year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)
+}
+
+fn get_year_len(year: i32) -> usize {
+ if is_leap_year(year) {
+ return 366;
+ }
+ 365
+}
+
+pub fn get_weekday_val(wk: &Weekday) -> usize {
+ match wk {
+ Weekday::Mon => 0,
+ Weekday::Tue => 1,
+ Weekday::Wed => 2,
+ Weekday::Thu => 3,
+ Weekday::Fri => 4,
+ Weekday::Sat => 5,
+ Weekday::Sun => 6,
+ }
+}
+
+pub struct BaseMasks {
+ mmask: Vec<usize>,
+ mdaymask: Vec<isize>,
+ nmdaymask: Vec<isize>,
+ wdaymask: Vec<usize>,
+ mrange: Vec<usize>,
+}
+
+fn base_year_masks(year: i32) -> BaseMasks {
+ let masks = MASKS.clone();
+ let firstyday = Utc.ymd(year, 1, 1).and_hms_milli(0, 0, 0, 0);
+ let yearlen = get_year_len(year);
+ let wday = get_weekday_val(&firstyday.weekday()) as usize;
+
+ if yearlen == 365 {
+ return BaseMasks {
+ mmask: masks.m365,
+ mdaymask: masks.mday365,
+ nmdaymask: masks.nmday365,
+ mrange: masks.m365range,
+ wdaymask: Vec::from(&masks.wday[wday..]),
+ };
+ }
+
+ BaseMasks {
+ mmask: masks.m366,
+ mdaymask: masks.mday366,
+ nmdaymask: masks.nmday366,
+ mrange: masks.m366range,
+ wdaymask: Vec::from(&masks.wday[wday..]),
+ }
+}
+
+pub fn pymod(a: isize, b: isize) -> isize {
+ let r = a % b;
+ // If r and b differ in sign, add b to wrap the result to the correct sign.
+ if (r > 0 && b < 0) || (r < 0 && b > 0) {
+ return r + b;
+ }
+ r
+}
+
+pub fn rebuild_year(year: i32, options: &ParsedOptions) -> YearInfo {
+ let firstyday = Utc.ymd(year, 1, 1).and_hms_milli(0, 0, 0, 0);
+
+ let yearlen = get_year_len(year);
+ let nextyearlen = get_year_len(year + 1);
+ let yearordinal = to_ordinal(&firstyday);
+ let yearweekday = get_weekday_val(&firstyday.weekday());
+
+ let base_masks = base_year_masks(year);
+
+ let mut result = YearInfo {
+ yearlen,
+ nextyearlen,
+ yearordinal,
+ yearweekday,
+ wnomask: None,
+ mmask: base_masks.mmask,
+ mdaymask: base_masks.mdaymask,
+ nmdaymask: base_masks.nmdaymask,
+ mrange: base_masks.mrange,
+ wdaymask: base_masks.wdaymask,
+ };
+
+ if options.byweekno.is_empty() {
+ return result;
+ }
+
+ let mut wnomask = vec![0; yearlen + 7];
+ let wyearlen;
+ let mut no1wkst = pymod((7 - yearweekday + options.wkst) as isize, 7);
+ let firstwkst = no1wkst;
+ if no1wkst >= 4 {
+ no1wkst = 0;
+ // Number of days in the year, plus the days we got
+ // from last year.
+ wyearlen = result.yearlen as isize + pymod(yearweekday as isize - options.wkst as isize, 7);
+ } else {
+ // Number of days in the year, minus the days we
+ // left in last year.
+ wyearlen = yearlen as isize - no1wkst;
+ }
+
+ let div = (wyearlen as f32 / 7.).floor() as isize;
+ let year_mod = pymod(wyearlen, 7);
+ //const numweeks = Math.floor(div + mod / 4)
+ let numweeks = div + (year_mod / 4);
+
+ for j in 0..options.byweekno.len() {
+ let mut n = options.byweekno[j];
+ if n < 0 {
+ n += (numweeks + 1) as isize;
+ }
+ if !(n > 0 && n <= numweeks) {
+ continue;
+ }
+ let mut i;
+ if n > 1 {
+ i = no1wkst + (n - 1) * 7;
+ if no1wkst != firstwkst {
+ i -= 7 - firstwkst;
+ }
+ } else {
+ i = no1wkst;
+ }
+
+ for _ in 0..7 {
+ wnomask[i as usize] = 1;
+ i += 1;
+ if result.wdaymask[i as usize] as usize == options.wkst {
+ break;
+ }
+ }
+ }
+
+ if options.byweekno.iter().any(|&wkno| wkno == 1) {
+ // Check week number 1 of next year as well
+ // orig-TODO : Check -numweeks for next year.
+ let mut i = no1wkst + numweeks * 7;
+ if no1wkst != firstwkst {
+ i -= 7 - firstwkst;
+ }
+ if i < yearlen as isize {
+ // If week starts in next year, we
+ // don't care about it.
+ for _ in 0..7 {
+ wnomask[i as usize] = 1;
+ i += 1;
+ if result.wdaymask[i as usize] as usize == options.wkst {
+ break;
+ }
+ }
+ }
+ }
+
+ if no1wkst > 0 {
+ // Check last week number of last year as
+ // well. If no1wkst is 0, either the year
+ // started on week start, or week number 1
+ // got days from last year, so there are no
+ // days from last year's last week number in
+ // this year.
+ let lnumweeks;
+ if !options.byweekno.iter().any(|&weekno| weekno == -1) {
+ let lyearweekday = get_weekday_val(&Utc.ymd(year - 1, 1, 1).weekday());
+
+ let lno1wkst = pymod((7 - lyearweekday + options.wkst) as isize, 7);
+
+ let lyearlen = get_year_len(year - 1);
+ let weekst;
+ if lno1wkst >= 4 {
+ //lno1wkst = 0;
+ weekst = lyearlen as isize + pymod((lyearweekday - options.wkst) as isize, 7);
+ } else {
+ weekst = yearlen as isize - no1wkst;
+ }
+
+ lnumweeks = 52 + (pymod(weekst, 7) / 4) as isize;
+ } else {
+ lnumweeks = -1 as isize;
+ }
+
+ if options.byweekno.iter().any(|&weekno| weekno == lnumweeks) {
+ for i in 0..no1wkst {
+ wnomask[i as usize] = 1;
+ }
+ }
+ }
+
+ result.wnomask = Some(wnomask);
+
+ result
+}