A highly optimized, auto-detecting, bulletproof date parsing package for Dart and Flutter. Automatically resolves, parses, and reformats date strings without requiring you to manually specify the input pattern. Perfect for handling varying user inputs, erratic API responses, or inconsistent legacy databases.
- π Auto-Detect Format Routing: Instant pattern matching handles date formats automatically.
- β‘ Zero-Instantiation Access: Call static methods or top-level helpers directly without creating objects.
- π String Extensions: Perform fluid parsing and formatting directly on any
Stringliteral in your Flutter widgets. - π Rich IDE Hover Documentation: Every public method is fully documented with complete Dartdoc comments and interactive markdown code blocks for instant hover assistance in VS Code, Android Studio, and IntelliJ.
- π High-Performance Architecture: Built for zero-overhead hot paths (precompiled regular expressions, pre-grouped list allocations, cached common output formatters, and O(1) case capitalization map lookups).
- π 50+ Date Format Variations: Full support for ISO-8601, RFC-2822, European Dot-separated dates, US (Month/Day/Year) layouts, 2-digit years, and compact strings.
- π Case-Insensitive RFC/HTTP Header Parsing: Easily handles HTTP/RFC date formats in any case casing (
Mon,mon,MON). - π‘οΈ Logical Calendrical Validation: Rejects invalid dates automatically (e.g., April 31st, February 30th, month 13, non-leap year Feb 29ths).
- β Exhaustive Testing Suite: 85+ passing unit tests covering edge cases, leap years, timezone offsets, and bounds.
Add the dependency to your package's pubspec.yaml file:
environment:
sdk: ^3.12.0 # Supports Dart 3.12.0+ & Flutter 3.44.0+
dependencies:
universal_date_parser: ^1.1.4Then download the package:
dart pub getimport 'package:universal_date_parser/universal_date_parser.dart';
void main() {
// Format string directly
print('2025-11-21 14:20:30'.formatDate());
// Output: 21/11/2025 14:20
// Parse directly to native DateTime?
DateTime? parsed = '21.11.25'.tryParseDate();
print(parsed?.year); // Output: 2025
}import 'package:universal_date_parser/universal_date_parser.dart';
void main() {
// Direct formatting
String formatted = UniversalDateParser.format('11/21/25', outputDateFormat: 'yyyy-MM-dd');
print(formatted); // Output: 2025-11-21
// Direct native DateTime parsing
DateTime dt = UniversalDateParser.parse('202511211420');
print(dt.hour); // Output: 14
}import 'package:universal_date_parser/universal_date_parser.dart';
void main() {
print(formatDate('Mon, 21 Nov 2025 14:20:00 +0530')); // 21/11/2025 14:20
DateTime? dt = tryParseDate('21.11.2025');
}The parser matches, detects, and falls back to a massive catalog of date variations:
2025-11-21T14:20:00.000Z(UTC Specifier)2025-11-21T14:20:00+05:30(Timezone Offset)2025-11-21T14:20:00.123456(Microsecond Accuracy)2025-11-21(Date only)
dd/MM/yyyy HH:mm:ss/dd/MM/yyyy HH:mm/dd/MM/yyyy(e.g.,21/11/2025)yyyy/MM/dd HH:mm:ss/yyyy/MM/dd HH:mm/yyyy/MM/dd(e.g.,2025/11/21)dd/MM/yy HH:mm:ss/dd/MM/yy(e.g.,21/11/25)MM/dd/yyyy HH:mm:ss/MM/dd/yyyy(e.g.,11/21/2025- US Format)MM/dd/yy HH:mm:ss/MM/dd/yy(e.g.,11/21/25- US 2-digit format)
yyyy-MM-dd HH:mm:ss/yyyy-MM-dd HH:mm/yyyy-MM-dd(e.g.,2025-11-21)dd-MM-yyyy HH:mm:ss/dd-MM-yyyy HH:mm/dd-MM-yyyy(e.g.,21-11-2025)dd-MM-yy HH:mm:ss/dd-MM-yy(e.g.,21-11-25)MM-dd-yyyy HH:mm:ss/MM-dd-yyyy(e.g.,11-21-2025- US format)MM-dd-yy(e.g.,11-21-25- US 2-digit format)
dd.MM.yyyy HH:mm:ss/dd.MM.yyyy HH:mm/dd.MM.yyyy(e.g.,21.11.2025)yyyy.MM.dd HH:mm:ss/yyyy.MM.dd(e.g.,2025.11.21)MM.dd.yyyy HH:mm:ss/MM.dd.yyyy(e.g.,11.21.2025- US format)dd.MM.yy/MM.dd.yy(e.g.,21.11.25,11.21.25- 2-digit variants)
dd MMM yyyy HH:mm:ss/dd MMM yyyy(e.g.,21 Nov 2025)MMM dd, yyyy HH:mm:ss/MMM dd, yyyy(e.g.,Nov 21, 2025)
yyyyMMdd(e.g.,20251121)yyyyMMddHHmm(e.g.,202511211420)yyyyMMddHHmmss(e.g.,20251121142030)
Mon, 21 Nov 2025 14:20:00 +05:30(Proper case)mon, 21 nov 2025 14:20:00 +0530(Lowercase, flat timezone)MON, 21 NOV 2025 14:20:00(Uppercase, no timezone)Fri, 25 Dec 2025 23:59:59 GMT(GMT Standard label)
Output formatted strings are highly customizable by specifying outputDateFormat during calls:
final input = '2025-11-21 14:20:30';
UniversalDateParser.format(input, outputDateFormat: 'yyyy-MM-dd');
// Output: 2025-11-21
UniversalDateParser.format(input, outputDateFormat: 'EEEE, MMMM d, yyyy');
// Output: Friday, November 21, 2025
UniversalDateParser.format(input, outputDateFormat: 'dd MMM yyyy HH:mm:ss');
// Output: 21 Nov 2025 14:20:30UniversalDateParser offers multiple, highly flexible ways to use the library depending on your architecture:
Parse dates statically anywhere in your code without instantiating objects.
UniversalDateParser.tryParse(String date)Parses any supported format and returns a native [DateTime] object. Returnsnullif parsing fails.DateTime? parsed = UniversalDateParser.tryParse('21/11/2025 14:20');
UniversalDateParser.parse(String date)Parses and returns a native [DateTime] object. Throws a [FormatException] if parsing fails.DateTime parsed = UniversalDateParser.parse('2025.11.21');
UniversalDateParser.format(String date, {String outputDateFormat})Formats the date string automatically. Returns'Invalid date'if parsing fails.String display = UniversalDateParser.format('20251121');
Direct, fluid extension methods on standard String literals. Extremely convenient for direct use in Flutter widgets.
String.formatDate({String outputDateFormat})Formats this string automatically.Text('2025-11-21'.formatDate()) // Output widget: 21/11/2025 00:00
String.tryParseDate()Parses this string into a native [DateTime?].DateTime? dt = 'Mon, 21 Nov 2025 14:20:00'.tryParseDate();
String.parseDate()Parses this string into a native [DateTime]. Throws [FormatException] if invalid.DateTime dt = '202511211420'.parseDate();
Standard global functions available after importing the package.
tryParseDate(String date)βββΊ ReturnsDateTime?parseDate(String date)βββββΊ ReturnsDateTimeformatDate(String date, {String outputDateFormat})βββΊ ReturnsString
Ideal for object-oriented injections.
final parser = UniversalDateParser();
String display = parser.formatDate(date: '21/11/2025');- Direct Delimiter Insertion: Purely numeric strings (length 8, 12, 14) are pre-segmented with standard dash delimiters, allowing them to instantly bypass complex pattern parsing and resolve directly via
DateTime.tryParse(). - Precompiled Regex Assets: All Regular Expression objects are allocated once as
static finalmembers, removing heavy regex compile cycles during consecutive format runs. - O(1) Capitalization Normalization: Rather than looping and performing 19 sequential regex replacements for day/month casing in RFCs, a single-pass
\b[A-Za-z]{3}\breplacement resolves casing immediately via map lookup. - Grouped Memory References: Candidate detection lists are pre-allocated statically. Auto-detection directly returns static array references instead of generating, filtering, and mapping lists on the fly.
- Direct Format Caching: Pre-compiles the default output formatter
DateFormat('dd/MM/yyyy HH:mm')as a static final object to prevent initialization overhead.
While UniversalDateParser is built to be extremely flexible, developers must be aware of certain logic constraints:
When an ambiguous numeric date is passed (e.g., 05/06/2025), it is mathematically impossible to differentiate between June 5th (European/International) and May 6th (US format) without context.
- Resolution Behavior: The parser prioritizes International/European conventions (
dd/MM/yyyy) by default over US structures. Therefore,05/06/2025will always be resolved as June 5th, 2025. - US Fallback Resolution: If a US date is unambiguous (e.g.,
05/26/2025where the month cannot be 26), the International parser will reject it, and the fallback pipeline will automatically attempt and successfully parse it using the US formatter as May 26th, 2025.
Dates containing timezone offsets (e.g. 2025-11-21T14:20:00-12:00 or 2025-11-21T14:20:00.000Z) are parsed using Dart's native DateTime.tryParse().
- Resolution Behavior: Native Dart parsing converts these values into the local timezone of the host device.
- Developer Notice: If your local timezone offset shifts the date across a midnight boundary (for example, parsing an offset of
-12:00on a device set to+05:30local time), the resulting formatted date string will reflect the local date (e.g. transitioning from the 21st to the 22nd).
When parsing 2-digit years (such as 21/11/25 or 11-21-85):
- Resolution Behavior: The parser implements a fixed pivot window at year 80:
- Values under 80 resolve to the 21st Century (
20xx). E.g.,25->2025. - Values 80 and above resolve to the 20th Century (
19xx). E.g.,85->1985.
- Values under 80 resolve to the 21st Century (
Compact numeric sequences must be exactly 8, 12, or 14 characters long (yyyyMMdd, yyyyMMddHHmm, or yyyyMMddHHmmss). Numeric representations outside these lengths (e.g., a 10-digit number like 2025112114) cannot be safely auto-delimited and will fall back to "Invalid date".
The test suite covers happy paths, edge cases, boundaries, timezone offsets, leap years, static helper execution, and calendrical errors. To run the suite:
dart testOutput:
00:00 +85: All tests passed!To see the date parser resolve 30+ different formats in real time, execute the console example app:
dart run example/universal_date_parser_example.dartThis project is licensed under the MIT License - see the LICENSE file for details.