blob: c156b05cbb8e27d84d8485c9c9aebcd5d0b707fa [file] [log] [blame]
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Common date utility functions used by the date picker implementation
// NOTE: This is an internal implementation file. Even though there are public
// classes and functions defined here, they are only meant to be used by the
// date picker implementation and are not exported as part of the Material library.
// See pickers.dart for exactly what is considered part of the public API.
import '../material_localizations.dart';
/// Returns a [DateTime] with just the date of the original, but no time set.
DateTime dateOnly(DateTime date) {
return DateTime(date.year, date.month, date.day);
}
/// Returns true if the two [DateTime] objects have the same day, month, and
/// year.
bool isSameDay(DateTime dateA, DateTime dateB) {
return
dateA.year == dateB.year &&
dateA.month == dateB.month &&
dateA.day == dateB.day;
}
/// Determines the number of months between two [DateTime] objects.
///
/// For example:
/// ```
/// DateTime date1 = DateTime(year: 2019, month: 6, day: 15);
/// DateTime date2 = DateTime(year: 2020, month: 1, day: 15);
/// int delta = monthDelta(date1, date2);
/// ```
///
/// The value for `delta` would be `7`.
int monthDelta(DateTime startDate, DateTime endDate) {
return (endDate.year - startDate.year) * 12 + endDate.month - startDate.month;
}
/// Returns a [DateTime] with the added number of months and truncates any day
/// and time information.
///
/// For example:
/// ```
/// DateTime date = DateTime(year: 2019, month: 1, day: 15);
/// DateTime futureDate = _addMonthsToMonthDate(date, 3);
/// ```
///
/// `date` would be January 15, 2019.
/// `futureDate` would be April 1, 2019 since it adds 3 months and truncates
/// any additional date information.
DateTime addMonthsToMonthDate(DateTime monthDate, int monthsToAdd) {
return DateTime(monthDate.year, monthDate.month + monthsToAdd);
}
/// Computes the offset from the first day of the week that the first day of
/// the [month] falls on.
///
/// For example, September 1, 2017 falls on a Friday, which in the calendar
/// localized for United States English appears as:
///
/// ```
/// S M T W T F S
/// _ _ _ _ _ 1 2
/// ```
///
/// The offset for the first day of the months is the number of leading blanks
/// in the calendar, i.e. 5.
///
/// The same date localized for the Russian calendar has a different offset,
/// because the first day of week is Monday rather than Sunday:
///
/// ```
/// M T W T F S S
/// _ _ _ _ 1 2 3
/// ```
///
/// So the offset is 4, rather than 5.
///
/// This code consolidates the following:
///
/// - [DateTime.weekday] provides a 1-based index into days of week, with 1
/// falling on Monday.
/// - [MaterialLocalizations.firstDayOfWeekIndex] provides a 0-based index
/// into the [MaterialLocalizations.narrowWeekdays] list.
/// - [MaterialLocalizations.narrowWeekdays] list provides localized names of
/// days of week, always starting with Sunday and ending with Saturday.
int firstDayOffset(int year, int month, MaterialLocalizations localizations) {
// 0-based day of week for the month and year, with 0 representing Monday.
final int weekdayFromMonday = DateTime(year, month).weekday - 1;
// 0-based start of week depending on the locale, with 0 representing Sunday.
int firstDayOfWeekIndex = localizations.firstDayOfWeekIndex;
// firstDayOfWeekIndex recomputed to be Monday-based, in order to compare with
// weekdayFromMonday.
firstDayOfWeekIndex = (firstDayOfWeekIndex - 1) % 7;
// Number of days between the first day of week appearing on the calendar,
// and the day corresponding to the first of the month.
return (weekdayFromMonday - firstDayOfWeekIndex) % 7;
}
/// Returns the number of days in a month, according to the proleptic
/// Gregorian calendar.
///
/// This applies the leap year logic introduced by the Gregorian reforms of
/// 1582. It will not give valid results for dates prior to that time.
int getDaysInMonth(int year, int month) {
if (month == DateTime.february) {
final bool isLeapYear = (year % 4 == 0) && (year % 100 != 0) ||
(year % 400 == 0);
if (isLeapYear)
return 29;
return 28;
}
const List<int> daysInMonth = <int>[31, -1, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
return daysInMonth[month - 1];
}