Jai Techie
Jai Techie

Reputation: 1957

How to get network DateTime.Now()?

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?

Upvotes: 28

Views: 17410

Answers (7)

Anandh Krishnan
Anandh Krishnan

Reputation: 5984

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

Upvotes: 3

Karam Helmi
Karam Helmi

Reputation: 1

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);
}

Upvotes: 0

bhavik13
bhavik13

Reputation: 117

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();

Upvotes: -4

nitroplr
nitroplr

Reputation: 109

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.');
        }
      }

Upvotes: 4

nitroplr
nitroplr

Reputation: 109

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);
  }
}

Upvotes: 3

Amon C
Amon C

Reputation: 1808

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');
}

Upvotes: 26

Brett Young
Brett Young

Reputation: 306

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());
}}

Upvotes: 6

Related Questions