-
-
Save apgapg/84d855e41c0134a34ff8b2cf034ad249 to your computer and use it in GitHub Desktop.
import 'package:intl/intl.dart'; | |
import 'package:meta/meta.dart'; | |
void main() { | |
print(DateUtils.formatISOTime(DateTime.now())); | |
print(DateUtils.getCurrentISOTimeString()); | |
} | |
class DateUtils { | |
///Converts DateTime to ISO format | |
///Output: 2020-09-16T20:41:09.331+05:30 | |
static String formatISOTime(DateTime date) { | |
var duration = date.timeZoneOffset; | |
if (duration.isNegative) | |
return (date.toIso8601String() + | |
"-${duration.inHours.toString().padLeft(2, '0')}:${(duration.inMinutes - (duration.inHours * 60)).toString().padLeft(2, '0')}"); | |
else | |
return (date.toIso8601String() + | |
"+${duration.inHours.toString().padLeft(2, '0')}:${(duration.inMinutes - (duration.inHours * 60)).toString().padLeft(2, '0')}"); | |
} | |
///get ISO time String from DateTime | |
///Output: 2020-09-16T20:42:38.629+05:30 | |
static String getCurrentISOTimeString({DateTime dateTime}) { | |
var date = dateTime ?? DateTime.now(); | |
//Time zone may be null in dateTime hence get timezone by datetime | |
var duration = DateTime.now().timeZoneOffset; | |
if (duration.isNegative) | |
//TODO: convert duration to abs value instead of below params | |
return (date.toIso8601String() + | |
"-${duration.inHours.abs().toString().padLeft(2, '0')}:${(duration.inMinutes.abs() - (duration.inHours.abs() * 60)).toString().padLeft(2, '0')}"); | |
else | |
return (date.toIso8601String() + | |
"+${duration.inHours.toString().padLeft(2, '0')}:${(duration.inMinutes - (duration.inHours * 60)).toString().padLeft(2, '0')}"); | |
} | |
} | |
LIVE DartPad: https://dartpad.dev/84d855e41c0134a34ff8b2cf034ad249
Be aware that it will fail when the given datetime was parsed from an iso string with offset:
formatISOTime(DateTime.parse('2000-04-22T01:00:00-05:00'));
That's because now dart will return the date with a trailing Z
for zero offset.
So it will end up with 2 offsets specified in the final string:
// note inclusion of Z character befiore -05:00
2000-04-22T01:00:00Z-05:00
That cannot be parsed back:
// note inclusion of Z character befiore -05:00
DateTime.parse('2000-04-22T01:00:00Z-05:00'); // throw invalid date string
Fixed the double offset issue:
static String formatISOTime(DateTime date) {
final iso = date.toIso8601String();
if (iso.endsWith("Z")) {
return iso;
}
var duration = date.timeZoneOffset;
if (duration.isNegative)
return (iso +
"-${duration.inHours.toString().padLeft(2, '0')}:${(duration.inMinutes - (duration.inHours * 60)).toString().padLeft(2, '0')}");
else
return (iso +
"+${duration.inHours.toString().padLeft(2, '0')}:${(duration.inMinutes - (duration.inHours * 60)).toString().padLeft(2, '0')}");
}
@gazialankus thanks for sharing but I wonder if date.toIso8601String
could return a time offset other that Z?
I personally adopted a slightly different approach by building the whole iso string part by part, so that we don't depend on something that could potentially break.
String getIsoDatetime(DateTime date) {
// make date string without offset
final month = date.month.toString().padLeft(2, '0');
final day = date.day.toString().padLeft(2, '0');
final hour = date.hour.toString().padLeft(2, '0');
final minute = date.minute.toString().padLeft(2, '0');
final second = date.second.toString().padLeft(2, '0');
final datetimeString =
'${date.year}-${month}-${day}T${hour}:${minute}:${second}.000';
// make offset string
final duration = date.timeZoneOffset;
final offsetHours = duration.inHours.abs().toString().padLeft(2, '0');
final offsetMinutes =
(duration.inMinutes.abs() - (duration.inHours.abs() * 60))
.toString()
.padLeft(2, '0');
final offsetString = "$offsetHours:$offsetMinutes";
// offset positive/negative
if (duration.isNegative)
return datetimeString + "-" + offsetString;
else
return datetimeString + "+" + offsetString;
;
}
It worked well so far that way,
DateTime says it's either Z or no Z, but yeah maybe it could change one day. https://api.dart.dev/stable/2.10.4/dart-core/DateTime/toIso8601String.html
@gsouf thank you for sharing your solution. It's nice to have an alternative if things fail.
Thank you for sharing.
I did few changes on it:
class DateUtils {
///Converts DateTime to ISO format
///Output: 2020-09-16T20:41:09.331+05:30
static String formatISOTime(DateTime date) {
var duration = date.timeZoneOffset;
return "${date.toIso8601String().replaceAll('Z', '')}${duration.isNegative ? "-" : "+"}${_formatTimeZoneOffsetISO(duration)}";
}
static String _formatTimeZoneOffsetISO(Duration duration) {
duration = duration.abs();
return "${duration.inHours.toString().padLeft(2, '0')}:${(duration.inMinutes - (duration.inHours * 60)).toString().padLeft(2, '0')}";
}
///get ISO time String from DateTime
///Output: 2020-09-16T20:42:38.629+05:30
static String getCurrentISOTimeString({DateTime? dateTime}) {
return formatISOTime(DateTime.now());
}
}
You have a big bug there, please remove the negative logic.
If you are in a timezone that is negative you will have double minus
/// converts [date] into into string format
/// Example:
/// * Positive: (UK) `2020-09-16T11:55:01.802248+00:00`
/// * Negative: (Canada) `2020-09-16T11:55:01.802248-08:00`
static String formatISOTime(DateTime date) {
var duration = date.timeZoneOffset;
/// If the user is in Canada the time zone is GMT-8 then the signal will need to be negative.
/// Because we already get the minus from the hours in the string then we don't need to add it to the string.
/// In the case the timezone is GMT-0 or higher then the sign will need to be positive.
var timezoneSignal = !(duration.isNegative) ? '+' : '';
var dateString = (date.toIso8601String() + "${timezoneSignal}${duration.inHours.toString().padLeft(2, '0')}:${(duration.inMinutes - (duration.inHours * 60)).toString().padLeft(2, '0')}");
return dateString;
}
@loonix, the code will not have a double minus if it's using the absolute value of the duration (.abs()), but your suggestion would also work.
thanks for this!