28

In flutter DateTime.now()returns the device date and time. Users sometimes change their internal clock and using DateTime.now() can give the wrong results.

  1. How can I get Network/Server Current DateTime in flutter?
  2. Is it possible to get Network/Server Current DateTime Without using any packages?
3
  • While I see that this question got quite a few upvotes, and so did the most popular answer (so apparently they are useful to some people), but I really don't think that there is such thing as "Network/Server Current DateTime". Why don't you trust your user (and their device) to have a "correctly" set up clock? Are you doing some kind of security solution? Which parties are you willing to trust?
    – cubuspl42
    Commented Feb 3, 2022 at 18:14
  • There's a decent chance that the only real solution to a problem you might have is implementing your checks on the backend you control. But that's of course just speculation.
    – cubuspl42
    Commented Feb 3, 2022 at 18:18
  • 2
    Lol, 💀 trust your users?, Imagine you're writing an app that collects data from user, say maybe daily logging of transactions and the payments received, and they're not meant to go back to an already closed day to edit figures, they could get around this by changing their device time and opening the app, and it'll let them access the past date like it's today, I don't know about you, but saying to trust your user sounds really shallow Commented Nov 27, 2022 at 22:00

7 Answers 7

25

It's not possible without any API. You can use ntp plugin:

A plugin that allows you to get precise time from Network Time Protocol (NTP). It implements the whole NTP protocol in dart.

This is useful for time-based events since DateTime.now() returns the time of the device. Users sometimes change their internal clock and using DateTime.now() can give the wrong result. You can just get clock offset [NTP.getNtpTime] and apply it manually to DateTime.now() object when needed (just add offset as milliseconds duration), or you can get already formatted [DateTime] object from [NTP.now].

Add this to your package's pubspec.yaml file:

dependencies:
  ntp: ^1.0.7

Then add the code like this:

import 'package:ntp/ntp.dart';

Future<void> main() async {
  DateTime _myTime;
  DateTime _ntpTime;

  /// Or you could get NTP current (It will call DateTime.now() and add NTP offset to it)
  _myTime = await NTP.now();

  /// Or get NTP offset (in milliseconds) and add it yourself
  final int offset = await NTP.getNtpOffset(localTime: DateTime.now());
  _ntpTime = _myTime.add(Duration(milliseconds: offset));

  print('My time: $_myTime');
  print('NTP time: $_ntpTime');
  print('Difference: ${_myTime.difference(_ntpTime).inMilliseconds}ms');
}
3
  • 3
    Is there a web alternative for ntp package? Since ntp doesn't support Flutter web, how can I get network time for a web app?
    – rasitayaz
    Commented Jun 11, 2021 at 9:57
  • You can check the firebase network timestap. Or you can use any third-party API and call JSON request.
    – Amon C
    Commented Jun 14, 2021 at 10:50
  • Note, that in this case the trust is put on Google, as that's the time server this package is using by default. Also note that NTP, as far as I know, does not support any kind of certificates. If you, let's say, want to protect your online multiplayer game from clock-based cheating with this solution, it's a bad idea. It's an okeyish idea only if you don't trust the user to have the correct local time but you are perfectly fine with the fact that nothing really stops the user from spoofing the timestamps on the NTP level.
    – cubuspl42
    Commented Feb 3, 2022 at 18:26
6

Try using the world clock api. Also, know that there is a chance the api could fail at some point... So I would recommend using a try-catch block around the http call, and if it does happen to fail, just return regular local time of the device....

  Future<void> getTime()async{
  var res = await http.get(Uri.parse('http://worldclockapi.com/api/json/est/now'));
  if (res.statusCode == 200){
  print(jsonDecode(res.body).toString());
}}
2
  • Add precise explanation, this can be better answer if you do.
    – Yadu
    Commented Feb 3, 2022 at 9:10
  • 3
    this URI is too slow. https://worldtimeapi.org/api/timezone/Etc/UTC is much faster
    – Andrey
    Commented Jul 2, 2023 at 12:51
4

I decided to go at this a different route since I'm already using Firebase. I had never used cloud functions before but I like this option better since I'm not reliant on api calls (some of which consider a ping more than once every four minutes a denial of service attack).

  1. firebase init functions
  2. flutter pub add cloud_functions
  3. In the generated index.js file in the functions folder add this code for the cloud function:
    const functions = require("firebase-functions");
    const admin = require('firebase-admin');
    admin.initializeApp();
    
    exports.timestamp = functions.https.onCall((data, context) => {
        // verify Firebase Auth ID token
        if (!context.auth) {
            return 'Authentication Required!';
        }
        let date = new Date();
        return date.toJSON();
    });
  1. firebase deploy --only functions Then in the dart code to call the function looks like this to return a network DateTime:
    final _functions = FirebaseFunctions.instance;
    
      Future<DateTime> getDateTime() async {
        try {
          final result = await _functions.httpsCallable('timestamp').call();
          return DateTime.parse(result.data);
        }on FirebaseFunctionsException  catch (error) {
          log(error.code);
          log(error.message!);
          log(error.details);
          throw Exception('Error getting datetime from cloud function.');
        }
      }
1
  • Your firebase functions answer saved me from my humble beginnings. However, since it has been a year since he wrote the code, several errors occurred to me, and this comment is for developers who will use firebase functions using this answer. const admin = require("firebase-admin"); exports.timestamp = functions.region("asia-northeast3").https.onCall(() => { const date = new Date();
    – Bishop03
    Commented Oct 27, 2023 at 16:42
3

This is my network time DateTime getNow() method. It is a global method that only gets the network time every two minutes. My app is not super time sensitive but I have run into some issues with people's clock's being off by a couple minutes. It just pings worldtimeapi.org at most every 2 minutes (you will get errors if you ping them too often) and uses their returned time to store an offset to modify the local datetime by. If there are errors with the http call, it falls back to the user's time. I'm also tracking the number of calls to this method just to help debug some timers I have to make sure they are getting disposed of properly.

The problem I had with worldclockapi is it was only accurate to the minute. I could have been doing something wrong but I solved it with using a different api. Here is the code:

int _nowOffset = 0;
int _lastHttpGet = 0;
int _nowCalls = 0;
Future<DateTime> getNow() async {
  try {
    _nowCalls++;
    DateTime nowLocal = DateTime.now();
    if ((nowLocal.millisecondsSinceEpoch - _lastHttpGet) > (oneMinuteMilliSeconds * 2)) {
      _lastHttpGet = nowLocal.millisecondsSinceEpoch;
      var res = await http.get(Uri.parse('https://worldtimeapi.org/api/timezone/Etc/UTC'));
      if (res.statusCode == 200) {
        //print(jsonDecode(res.body).toString());
        Map<String, dynamic> json = jsonDecode(res.body);
        DateTime nowHttp = DateTime.parse(json['datetime']);
        _nowOffset = nowLocal.millisecondsSinceEpoch - nowHttp.millisecondsSinceEpoch;
        if (_nowOffset > 0) {
          _nowOffset *= -1;
        }
        log('http $_nowCalls');
        return nowHttp;
      }
    }
    return DateTime.fromMillisecondsSinceEpoch(nowLocal.millisecondsSinceEpoch + _nowOffset);
  } catch (e, stack) {
    log('{http error: now calls: $_nowCalls $e\n $stack}');
    return DateTime.fromMillisecondsSinceEpoch(DateTime.now().millisecondsSinceEpoch + _nowOffset);
  }
}
3

You can use this plugin ntp.

import 'package:ntp/ntp.dart';

final int offset = await NTP.getNtpOffset(
        localTime: DateTime.now(), lookUpAddress: "time.google.com");
DateTime internetTime = DateTime.now().add(Duration(milliseconds: offset));

Or there are plenty of API's available

here is an example GET API for Indian time

http://worldtimeapi.org/api/timezone/Asia/Kolkata

The response will be like

  {
      "abbreviation": "IST",
      "client_ip": "45.125.117.46",
      "datetime": "2022-02-26T10:50:43.406519+05:30",
      "day_of_week": 6,
      "day_of_year": 57,
      "dst": false,
      "dst_from": null,
      "dst_offset": 0,
      "dst_until": null,
      "raw_offset": 19800,
      "timezone": "Asia/Kolkata",
      "unixtime": 1645852843,
      "utc_datetime": "2022-02-26T05:20:43.406519+00:00",
      "utc_offset": "+05:30",
      "week_number": 8
    }

If you dont know your country zone just call this API to get all timezones in the world

http://worldtimeapi.org/api/timezone/

https://worldtimeapi.org/api/timezone/Etc/UTC

0

in my case i have used firebase cloud functions to retrieve the time just call this function through an api call and the response will be in isostring you would just have to convert it by doing DateTime.parse(response.body).

this is the firebase javascript function code

exports.getDateTime = functions.https.onRequest((request, response) => {
    const londonTime = new Date().toLocaleString('en-GB', { timeZone: 'Europe/London' });
    const londonTimeISO = new Date(londonTime).toISOString();
    response.send(londonTimeISO);
});

and this is the flutter function.

Future<DateTime> getNetworkDateTime() async {
  final url = Uri.parse(
    'https://us-central1-service-finder-27584.cloudfunctions.net/getDateTime',
  );

  final response = await http.post(
    url,
    headers: {
      'Content-Type': 'application/json',
    },
    body: json.encode(
      {},
    ),
  );
  return DateTime.parse(response.body);
}
-4

it is possible to get Network/Server Current DateTime Without using any packages.

Use this to get the Network/Server Current DateTime:-

DateTime now =
        DateTime.now().isUtc ? DateTime.now() : DateTime.now().toUtc();

Not the answer you're looking for? Browse other questions tagged or ask your own question.