@@ -25,7 +25,7 @@ use crate::format::{Item, Numeric, Pad};
2525use  crate :: month:: Months ; 
2626use  crate :: naive:: { IsoWeek ,  NaiveDateTime ,  NaiveTime } ; 
2727use  crate :: oldtime:: Duration  as  OldDuration ; 
28- use  crate :: { Datelike ,  Duration ,  Weekday } ; 
28+ use  crate :: { Datelike ,  Duration ,  Month ,   Weekday } ; 
2929
3030use  super :: internals:: { self ,  DateImpl ,  Mdf ,  Of ,  YearFlags } ; 
3131use  super :: isoweek; 
@@ -236,6 +236,49 @@ fn test_date_bounds() {
236236} 
237237
238238impl  NaiveDate  { 
239+     /// Create a `NaiveDate` of the first day of the given year 
240+ /// 
241+ /// This takes an `i16` rather than `i32` to ensure it is not 
242+ /// out of the allowed range 
243+ pub  fn  start_year ( year :  i16 )  -> NaiveDate  { 
244+         // ideally this unwrap can be later removed 
245+         Self :: from_ymd_opt ( year. into ( ) ,  1 ,  1 ) . unwrap ( ) 
246+     } 
247+ 
248+     /// Create a `NaiveDate` of the last day of the given year 
249+ /// 
250+ /// This takes an `i16` rather than `i32` to ensure it is not 
251+ /// out of the allowed range 
252+ pub  fn  end_year ( year :  i16 )  -> NaiveDate  { 
253+         // ideally this unwrap can be later removed 
254+         Self :: from_ymd_opt ( i32:: from ( year)  + 1 ,  1 ,  1 ) . unwrap ( ) . pred_opt ( ) . unwrap ( ) 
255+     } 
256+ 
257+     /// Create a `NaiveDate` of the first day of the given year and month 
258+ /// 
259+ /// This takes an `i16` rather than `i32` to ensure it is not 
260+ /// out of the allowed range 
261+ pub  fn  start_month ( year :  i16 ,  month :  Month )  -> NaiveDate  { 
262+         // ideally this unwrap can be later removed 
263+         Self :: from_ymd_opt ( year. into ( ) ,  month. number_from_month ( ) ,  1 ) . unwrap ( ) 
264+     } 
265+ 
266+     /// Create a `NaiveDate` of the ;ast day of the given year and month 
267+ /// 
268+ /// This takes an `i16` rather than `i32` to ensure it is not 
269+ /// out of the allowed range 
270+ pub  fn  end_month ( year :  i16 ,  month :  Month )  -> NaiveDate  { 
271+         // ideally this unwrap can be later removed 
272+         let  start = Self :: start_month ( year,  month) ; 
273+ 
274+         ( start + Months :: new ( 1 ) ) . pred_opt ( ) . unwrap ( ) 
275+     } 
276+ 
277+     /// Create a `NaiveDateTime` at midnight on the given `NaiveDate` 
278+ pub  fn  start_time ( & self )  -> NaiveDateTime  { 
279+         self . and_time ( NaiveTime :: MIN ) 
280+     } 
281+ 
239282    /// Makes a new `NaiveDate` from year and packed ordinal-flags, with a verification. 
240283fn  from_of ( year :  i32 ,  of :  Of )  -> Option < NaiveDate >  { 
241284        if  ( MIN_YEAR ..=MAX_YEAR ) . contains ( & year)  && of. valid ( )  { 
@@ -2166,13 +2209,87 @@ mod tests {
21662209    use  super :: { 
21672210        Days ,  Months ,  NaiveDate ,  MAX_DAYS_FROM_YEAR_0 ,  MAX_YEAR ,  MIN_DAYS_FROM_YEAR_0 ,  MIN_YEAR , 
21682211    } ; 
2212+     use  crate :: naive:: internals:: YearFlags ; 
21692213    use  crate :: oldtime:: Duration ; 
2170-     use  crate :: { Datelike ,  Weekday } ; 
2214+     use  crate :: { Datelike ,  Month ,   Weekday } ; 
21712215    use  std:: { 
21722216        convert:: { TryFrom ,  TryInto } , 
21732217        i32,  u32, 
21742218    } ; 
21752219
2220+     #[ test]  
2221+     fn  test_helpers ( )  { 
2222+         let  months = & [ 
2223+             Month :: January , 
2224+             Month :: February , 
2225+             Month :: March , 
2226+             Month :: April , 
2227+             Month :: May , 
2228+             Month :: June , 
2229+             Month :: July , 
2230+             Month :: August , 
2231+             Month :: September , 
2232+             Month :: October , 
2233+             Month :: November , 
2234+             Month :: December , 
2235+         ] ; 
2236+ 
2237+         fn  days_in_month ( month :  Month ,  flags :  YearFlags )  -> u8  { 
2238+             match  month { 
2239+                 Month :: January  => 31 , 
2240+                 Month :: February  if  flags. ndays ( )  == 366  => 29 , 
2241+                 Month :: February  => 28 , 
2242+                 Month :: March  => 31 , 
2243+                 Month :: April  => 30 , 
2244+                 Month :: May  => 31 , 
2245+                 Month :: June  => 30 , 
2246+                 Month :: July  => 31 , 
2247+                 Month :: August  => 31 , 
2248+                 Month :: September  => 30 , 
2249+                 Month :: October  => 31 , 
2250+                 Month :: November  => 30 , 
2251+                 Month :: December  => 31 , 
2252+             } 
2253+         } 
2254+         for  year in  0 ..=9999  { 
2255+             assert_eq ! ( NaiveDate :: start_year( year) . to_string( ) ,  format!( "{:04}-01-01" ,  year) ) ; 
2256+             assert_eq ! ( NaiveDate :: end_year( year) . to_string( ) ,  format!( "{:04}-12-31" ,  year) ) ; 
2257+             assert_eq ! ( 
2258+                 NaiveDate :: start_year( year) . start_time( ) . to_string( ) , 
2259+                 format!( "{:04}-01-01 00:00:00" ,  year) 
2260+             ) ; 
2261+ 
2262+             for  month in  months { 
2263+                 assert_eq ! ( 
2264+                     NaiveDate :: start_month( year,  * month) . to_string( ) , 
2265+                     format!( "{:04}-{:02}-01" ,  year,  month. number_from_month( ) ) 
2266+                 ) ; 
2267+                 assert_eq ! ( 
2268+                     NaiveDate :: end_month( year,  * month) . to_string( ) , 
2269+                     format!( 
2270+                         "{:04}-{:02}-{:02}" , 
2271+                         year, 
2272+                         month. number_from_month( ) , 
2273+                         days_in_month( * month,  YearFlags :: from_year( year. into( ) ) ) 
2274+                     ) 
2275+                 ) ; 
2276+             } 
2277+         } 
2278+         for  year in  i16:: MIN ..=i16:: MAX  { 
2279+             NaiveDate :: start_year ( year) ; 
2280+             NaiveDate :: end_year ( year) ; 
2281+             assert_eq ! ( 
2282+                 NaiveDate :: start_year( year) , 
2283+                 NaiveDate :: start_year( year) . start_time( ) . date( ) 
2284+             ) ; 
2285+ 
2286+             for  month in  months { 
2287+                 NaiveDate :: start_month ( year,  * month) ; 
2288+                 NaiveDate :: end_month ( year,  * month) ; 
2289+             } 
2290+         } 
2291+     } 
2292+ 
21762293    #[ test]  
21772294    fn  diff_months ( )  { 
21782295        // identity 
0 commit comments