Skip to content

Commit

Permalink
The year 0 will now render as 1BC for CSL
Browse files Browse the repository at this point in the history
CSL year formatting will now use only a single code path. This code has been fixed to treat the year zero correctly. Unlike what has been suggested in #185, AD continues to be used as a postfix to comply with https://docs.citationstyles.org/en/stable/specification.html?#ad-and-bc

Fixes #185
  • Loading branch information
reknih committed Oct 10, 2024
1 parent 9e30220 commit ce3448e
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 25 deletions.
61 changes: 48 additions & 13 deletions src/csl/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -633,19 +633,9 @@ fn date_replacement<T: EntryLike>(

ElemChildren(vec![ElemChild::Text(Formatted {
text: if let Some(date) = date {
format!(
"{}{}",
if date.year > 0 { date.year } else { date.year.abs() + 1 },
if date.year < 1000 {
if date.year < 0 {
"BC"
} else {
"AD"
}
} else {
""
}
)
let mut s = String::with_capacity(4);
write_year(date.year, false, &mut s).unwrap();
s
} else if let Some(no_date) = ctx
.ctx(entry, cite_props.clone(), locale, term_locale, false)
.term(Term::Other(OtherTerm::NoDate), TermForm::default(), false)
Expand All @@ -658,6 +648,33 @@ fn date_replacement<T: EntryLike>(
})])
}

pub fn write_year<W: std::fmt::Write>(
year: i32,
short: bool,
w: &mut W,
) -> std::fmt::Result {
if short && year >= 1000 {
return write!(w, "{:02}", year % 100);
}

write!(
w,
"{}{}",
if year > 0 { year } else { year.abs() + 1 },
if year < 1000 {
if year <= 0 {
"BC"
} else {
// AD is used as a postfix, see
// https://docs.citationstyles.org/en/stable/specification.html?#ad-and-bc
"AD"
}
} else {
""
}
)
}

fn last_purpose_render<T: EntryLike + Debug>(
ctx: &StyleContext<'_>,
item: &SpeculativeItemRender<T>,
Expand Down Expand Up @@ -2887,4 +2904,22 @@ mod tests {
// }
}
}

#[test]
fn low_year_test() {
let yield_year = |year, short| {
let mut s = String::new();
write_year(year, short, &mut s).unwrap();
s
};

assert_eq!(yield_year(2021, false), "2021");
assert_eq!(yield_year(2021, true), "21");
assert_eq!(yield_year(0, false), "1BC");
assert_eq!(yield_year(-1, false), "2BC");
assert_eq!(yield_year(1, false), "1AD");
assert_eq!(yield_year(0, true), "1BC");
assert_eq!(yield_year(-1, true), "2BC");
assert_eq!(yield_year(1, true), "1AD");
}
}
15 changes: 3 additions & 12 deletions src/csl/rendering/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use crate::types::{ChunkedString, Date, MaybeTyped, Numeric};
use crate::PageRanges;

use super::taxonomy::EntryLike;
use super::{Context, ElemMeta, IbidState, SpecialForm, UsageInfo};
use super::{write_year, Context, ElemMeta, IbidState, SpecialForm, UsageInfo};

pub mod names;

Expand Down Expand Up @@ -769,17 +769,8 @@ fn render_date_part<T: EntryLike>(
write!(ctx, "{}", val).unwrap();
}
}
DateStrongAnyForm::Year(LongShortForm::Short) => {
write!(ctx, "{:02}", (val % 100).abs()).unwrap();
}
DateStrongAnyForm::Year(LongShortForm::Long) => {
write!(ctx, "{}", val.abs()).unwrap();
}
}

if let DateStrongAnyForm::Year(_) = form {
if date.year < 1000 {
ctx.push_str(if date.year < 0 { "BC" } else { "AD" });
DateStrongAnyForm::Year(brevity) => {
write_year(val, brevity == LongShortForm::Short, ctx).unwrap();
}
}
}
Expand Down

0 comments on commit ce3448e

Please sign in to comment.