General Datetime (Dynamic Calendar)

Issues Issues GitHub Pull Requests GitHub GitHub Repo stars

Flutter CI

A Flutter/Dart Package for working with dates across several calendar systems. Using a unified interface, you can convert, manipulate, and compare dates in Gregorian, Jalali (Persian Calendar), Hijri (Umm Al-Qura Calendar), and other calendar systems—all while preserving time components and handling timezone, leap year, and negative value normalization gracefully.

Features

  • Gregorian ↔ Other calendars: Convert between Gregorian and other dates with high precision, preserving time components (hours, minutes, seconds, milliseconds, and microseconds).

  • Leap Year Handling: Detect and correctly handle leap years and leap days, including automatic correction of invalid leap dates.

  • Custom Arithmetic: Perform date arithmetic using custom implementations of add, subtract, and difference that work directly on calendar fields.

  • Negative Normalization: Automatically normalize negative values in day, month, hour, minute, second, millisecond and microsecond components.

  • Time Zone Support: Retrieve the time zone name and offset matching Flutter’s DateTime behavior for both local and UTC dates.

  • Parsing and Formatting: Create JalaliDatetime instances from formatted strings and output a consistent string representation.

Installation

To use this plugin, you can add it to your Flutter project in one of two ways:

1. Add to pubspec.yaml

Include the following dependency in your pubspec.yaml file:

dependencies:
  jalali_datetime: ^0.1.1

2. Add directly from the terminal

Run the following command to add the plugin directly to your project:

flutter pub add jalali_datetime

Usage

Import the package into your Dart code. The library exposes a unified interface for working with dates across multiple calendar systems. For example, you can work with the Jalali calendar using the provided implementation:

import 'package:general_datetime/general_datetime.dart';
import 'package:shamsi_date/shamsi_date.dart'; // Your concrete implementation

void main() {
  // Create a Gregorian date and convert it to Jalali:
  JalaliDatetime jDate = JalaliDatetime.fromDatetime(DateTime(2025, 3, 1));
  print('Converted to Jalali: ${jDate.toString()}'); // e.g. "1403-12-11 00:00:00.000"

  // Create a Jalali date directly (auto-normalization applies):
  JalaliDatetime directDate = JalaliDatetime(1403, 12, 11, 14, 30);
  print('Direct Jalali: ${directDate.toString()}');

  // Perform arithmetic:
  JalaliDatetime futureDate = jDate.add(Duration(days: 5, hours: 3));
  print('Future Date: ${futureDate.toString()}');

  // Compare dates:
  bool isBefore = jDate.isBefore(JalaliDatetime(1403, 12, 12));
  print('Is jDate before 1403-12-12? $isBefore');

  // Parse a date string:
  JalaliDatetime parsed = JalaliDatetime.parse("1403-12-11 14:30:45.123456Z");
  print('Parsed Date: ${parsed.toString()}');

  // Time zone information:
  print('Time Zone Name: ${jDate.timeZoneName}');
  print('Time Zone Offset: ${jDate.timeZoneOffset}');
}

  • Checkout Example for complete explanation

API Overview

Factory Constructors

  • fromDatetime(DateTime datetime) Converts a Gregorian DateTime to a calendar-specific date (e.g. Jalali).

  • now() Returns the current date and time in the default calendar.

  • utc(...) Creates a UTC date with normalization.

  • fromSecondsSinceEpoch(...) Creates an instance from Unix seconds.

  • fromMillisecondsSinceEpoch(...) Creates an instance from Unix milliseconds.

  • fromMicrosecondsSinceEpoch(...) Creates an instance from Unix microseconds.

  • parse(String formattedString) and tryParse(String formattedString) Parse ISO-like formatted strings into a calendar date.

Core Properties

  • Date Components: year, month, day, hour, minute, second, millisecond, microsecond

  • Time Zone Information: timeZoneName and timeZoneOffset behave similar to Flutter’s DateTime.

  • isLeapYear Returns true if the current year is a leap year in the current calendar system.

  • dayOfYear Returns the day of the year (1-based).

  • julianDay The calculated Julian day number for the date.

Arithmetic & Comparison

  • Arithmetic Methods: add(Duration duration), subtract(Duration duration) Implemented independently (without relying on native DateTime arithmetic).

  • Difference: difference(dynamic other) returns a Duration representing the difference between two dates.

  • Comparison: compareTo(dynamic other), isBefore, isAfter, isAtSameMomentAs Compare calendar dates across systems.

Customization

Since this plugin is based on a general date interface, you can extend its functionality to support additional calendar systems.

Important

It’s critical that you implement a robust _normalize() method to ensure that any invalid date or time input is adjusted to a valid state, avoiding exceptions. Additionally, provide a private conversion function (e.g., _toCustomCalendar()) that converts from the base calendar (usually Gregorian) to your custom calendar. These helper functions must be private and only used within the factory constructors so that users always receive a fully normalized, valid date instance.

Tip

When adding support for a new calendar, it’s recommended to implement factory constructors that use a private “raw” constructor. This raw factory should create an instance with unmodified input data. Then, call private helper methods (e.g., _normalize() and a conversion method such as _toCustomCalendar()) to validate and adjust the values. This approach keeps raw data creation separate from data manipulation, making the code more modular and easier to debug.

Contributions

Contributions are welcome! If you have suggestions, fixes, or new features, please submit a pull request or open an issue on GitHub.

Licence

This project is licensed under the BSD 3-Clause License. See the LICENSE file for details.

Libraries

general_datetime
This file is startup of general_datetime library you can use the package consider the example