fix(defter): haftalar ayın günlerine göre (1–8, 9–15, 16–22, 23–son), defter bugünün haftasıyla açılır
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -52,20 +52,35 @@ pub struct Week {
|
||||
pub days: u32,
|
||||
}
|
||||
|
||||
/// Dönemi Pazartesi başlangıçlı haftalara böler.
|
||||
/// Baştaki ve sondaki kısmi haftalar ayrı hafta sayılır (KAKEIBO_PROMPT §6).
|
||||
/// Dönemi **ayın günlerine göre** haftalara böler (kullanıcı kararı, 2026-11-13):
|
||||
/// 1–8 → 1. hafta, 9–15 → 2., 16–22 → 3., 23–son gün → 4. hafta.
|
||||
///
|
||||
/// Gün numarası dönem başından sayılır (dönem 15'inde başlıyorsa 15–22 = 1. hafta).
|
||||
/// Genel kural: hafta sayısı `max(1, gün / 7)`; ilk hafta 8 gün, aradakiler 7 gün,
|
||||
/// son hafta kalan günler (6–12 gün). 28–31 günlük dönem → daima 4 hafta.
|
||||
/// Bütçe haftalara gün sayısıyla orantılı dağıtılır (`days`).
|
||||
pub fn weeks(start: Date, end_exclusive: Date) -> Vec<Week> {
|
||||
let mut out = Vec::new();
|
||||
let total = days_between(start, end_exclusive);
|
||||
if total <= 0 {
|
||||
return Vec::new();
|
||||
}
|
||||
let count = (total / 7).max(1);
|
||||
let mut out = Vec::with_capacity(count as usize);
|
||||
let mut cursor = start;
|
||||
while cursor < end_exclusive {
|
||||
// Bir sonraki Pazartesi (ya da dönem sonu, hangisi önce gelirse)
|
||||
let to_monday = 7 - i64::from(cursor.weekday().number_days_from_monday());
|
||||
let next = (cursor + Duration::days(to_monday)).min(end_exclusive);
|
||||
for i in 0..count {
|
||||
let len = if i == count - 1 {
|
||||
days_between(cursor, end_exclusive)
|
||||
} else if i == 0 {
|
||||
8
|
||||
} else {
|
||||
7
|
||||
};
|
||||
let next = cursor + Duration::days(len);
|
||||
out.push(Week {
|
||||
index: out.len() as u32 + 1,
|
||||
index: i as u32 + 1,
|
||||
start: cursor,
|
||||
last: next - Duration::days(1),
|
||||
days: days_between(cursor, next) as u32,
|
||||
days: len as u32,
|
||||
});
|
||||
cursor = next;
|
||||
}
|
||||
@@ -123,37 +138,69 @@ mod tests {
|
||||
assert!(parse_date("2028-02-29").is_some(), "artık yıl");
|
||||
}
|
||||
|
||||
fn summary(w: &[Week]) -> Vec<(u32, String, String, u32)> {
|
||||
w.iter()
|
||||
.map(|w| (w.index, format_date(w.start), format_date(w.last), w.days))
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn december_2026_weeks() {
|
||||
// 1 Aralık 2026 Salı → ilk hafta 6 gün (Sal–Paz), son hafta 4 gün (Pzt–Per)
|
||||
let w = weeks(d("2026-12-01"), d("2027-01-01"));
|
||||
let summary: Vec<(String, String, u32)> = w
|
||||
.iter()
|
||||
.map(|w| (format_date(w.start), format_date(w.last), w.days))
|
||||
.collect();
|
||||
fn month_weeks_follow_day_of_month() {
|
||||
// Kasım 2026 (1'i Pazar): 1–8, 9–15, 16–22, 23–30 → 4 hafta
|
||||
let w = weeks(d("2026-11-01"), d("2026-12-01"));
|
||||
assert_eq!(
|
||||
summary,
|
||||
summary(&w),
|
||||
vec![
|
||||
("2026-12-01".into(), "2026-12-06".into(), 6),
|
||||
("2026-12-07".into(), "2026-12-13".into(), 7),
|
||||
("2026-12-14".into(), "2026-12-20".into(), 7),
|
||||
("2026-12-21".into(), "2026-12-27".into(), 7),
|
||||
("2026-12-28".into(), "2026-12-31".into(), 4),
|
||||
(1, "2026-11-01".into(), "2026-11-08".into(), 8),
|
||||
(2, "2026-11-09".into(), "2026-11-15".into(), 7),
|
||||
(3, "2026-11-16".into(), "2026-11-22".into(), 7),
|
||||
(4, "2026-11-23".into(), "2026-11-30".into(), 8),
|
||||
]
|
||||
);
|
||||
assert_eq!(w.iter().map(|w| w.days).sum::<u32>(), 31);
|
||||
assert_eq!(w.last().unwrap().index, 5);
|
||||
// 31 gün → son hafta 23–31 (9 gün); Şubat → 23–28 (6 gün); artık yıl → 7 gün
|
||||
for (start, end, last_days) in [
|
||||
("2026-12-01", "2027-01-01", 9),
|
||||
("2027-02-01", "2027-03-01", 6),
|
||||
("2028-02-01", "2028-03-01", 7),
|
||||
] {
|
||||
let w = weeks(d(start), d(end));
|
||||
assert_eq!(w.len(), 4, "{start}");
|
||||
assert_eq!(w[3].start.day(), 23, "{start}");
|
||||
assert_eq!(w[3].days, last_days, "{start}");
|
||||
assert_eq!(
|
||||
w.iter().map(|w| i64::from(w.days)).sum::<i64>(),
|
||||
days_between(d(start), d(end))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn weeks_edge_cases() {
|
||||
// Pazartesi başlayan, tam 2 hafta
|
||||
let w = weeks(d("2026-11-30"), d("2026-12-14"));
|
||||
assert_eq!(w.len(), 2);
|
||||
assert!(w.iter().all(|w| w.days == 7));
|
||||
// Tek gün (Pazar)
|
||||
// Ay ortasında başlayan dönem: günler dönem başından sayılır
|
||||
let w = weeks(d("2026-12-15"), d("2027-01-15"));
|
||||
assert_eq!(
|
||||
summary(&w)
|
||||
.iter()
|
||||
.map(|x| (x.1.as_str(), x.3))
|
||||
.collect::<Vec<_>>(),
|
||||
vec![
|
||||
("2026-12-15", 8),
|
||||
("2026-12-23", 7),
|
||||
("2026-12-30", 7),
|
||||
("2027-01-06", 9)
|
||||
]
|
||||
);
|
||||
// Kısa dönemler: 13 gün → tek hafta, 14 gün → 8 + 6
|
||||
assert_eq!(summary(&weeks(d("2026-12-01"), d("2026-12-14"))).len(), 1);
|
||||
let w = weeks(d("2026-12-01"), d("2026-12-15"));
|
||||
assert_eq!((w[0].days, w[1].days), (8, 6));
|
||||
// Tek gün
|
||||
let w = weeks(d("2026-12-06"), d("2026-12-07"));
|
||||
assert_eq!((w.len(), w[0].days), (1, 1));
|
||||
// Uzun dönem (62 gün) → 8 hafta, son hafta ≤ 12 gün
|
||||
let w = weeks(d("2026-11-01"), d("2027-01-02"));
|
||||
assert_eq!(w.len(), 8);
|
||||
assert!(w.iter().all(|w| (6..=12).contains(&w.days)));
|
||||
// Boş aralık
|
||||
assert!(weeks(d("2026-12-07"), d("2026-12-07")).is_empty());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user