How to convert DateTime to TZDateTime in flutter?

瘦欲@ 提交于 2021-02-10 07:32:32

问题


I am trying to push local notification through my app by using flutter_local_notifications package and as on FlutterNotificationsPlugin the ".schedule" is deprecated I tried using ".zonedSchedule" but it requires TZDateTime value.

var androidDetails = AndroidNotificationDetails(t.id, "Task Notifier",
        "Notifies if you have a task scheduled at a particular time");
    var generalNotificationDetails =
        NotificationDetails(android: androidDetails);
    var now = DateTime.now();
    var scheduledTime = DateTime(
            now.year, now.month, _dayTasks.date.day, t.time.hour, t.time.minute)
        .subtract(Duration(minutes: 5));
    //use zonedSchedule once you figure out how to convert datetime to TZdatetime
    // await notifications.zonedSchedule(
    //     0, "Task", t.description, scheduledTime, generalNotificationDetails,
    //     androidAllowWhileIdle: true,
    //     uiLocalNotificationDateInterpretation:
    //         UILocalNotificationDateInterpretation.wallClockTime);
    await notifications.schedule(0, "Ideal Day Task", t.description,
        scheduledTime, generalNotificationDetails);

回答1:


Indeed, zonedSchedule() requires the TZDateTime value. The approach I took was to utilize another package to convert the original DateTime value to a TZDateTime value. Below is an excerpt of one implementation I've used. See the fifth line? It involves the function, TZDateTime.from(). It takes the DateTime you may have originally used and converts it to TZDateTime. However, it needs your current location. That's where the class, TimeZone, comes in.

    import 'package:timezone/timezone.dart' as tz;
    :
    :
    :

    final timeZone = TimeZone();

    // The device's timezone.
    String timeZoneName = await timeZone.getTimeZoneName();

    // Find the 'current location'
    final location = await timeZone.getLocation(timeZoneName);

    final scheduledDate = tz.TZDateTime.from(dateTime, location);

    try {
      await _flutterLocalNotificationsPlugin.zonedSchedule(
        id,
        title,
        body,
        scheduledDate,
        platformChannelSpecifics,
        androidAllowWhileIdle: androidAllowWhileIdle,
        payload: payload,
        uiLocalNotificationDateInterpretation:
            uiLocalNotificationDateInterpretation,
      );
    } catch (ex) {
      id = -1;
    }
    return id;

I quickly wrote the class, TimeZone. This class works with yet another plugin (flutter_native_timezone) that looks for the 'current location' of the device and provides the standard name for that locale:

import 'package:timezone/data/latest.dart';
import 'package:timezone/timezone.dart' as t;
import 'package:flutter_native_timezone/flutter_native_timezone.dart';

class TimeZone {
  factory TimeZone() => _this ?? TimeZone._();

  TimeZone._() {
    initializeTimeZones();
  }
  static TimeZone _this;

  Future<String> getTimeZoneName() async => FlutterNativeTimezone.getLocalTimezone();

  Future<t.Location> getLocation([String timeZoneName]) async {
    if(timeZoneName == null || timeZoneName.isEmpty){
      timeZoneName = await getTimeZoneName();
    }
    return t.getLocation(timeZoneName);
  }
}

Use that class, and you're good to go.




回答2:


I had just tried to solve the same problem. To understand this, we will need to have a basic understanding of platform channel.

https://flutter.dev/docs/development/platform-integration/platform-channels?tab=android-channel-kotlin-tab

Once we understand that, the code in the sample should become more understandable: https://github.com/MaikuB/flutter_local_notifications/blob/1fe78b9d129d674cd97cfba49734577b24c56925/flutter_local_notifications/example/android/app/src/main/java/com/dexterous/flutterlocalnotificationsexample/MainActivity.java

Concept in action:

First of all, we will need to import tz like so. This can be done in your main.dart or a helper file.

import 'package:timezone/data/latest.dart' as tz;
import 'package:timezone/timezone.dart' as tz;

To create a TZDateTime from a plain dateTime, we will need to use the device timezone through queried through the platform channel.

Future<void> configureLocalTimeZone() async {
  tz.initializeTimeZones();
  final String timeZoneName = await platform.invokeMethod('getTimeZoneName');
  tz.setLocalLocation(tz.getLocation(timeZoneName));
}

Where getTimeZoneName is implemented in the platform specific implementation.

Be sure to call configureLocalTimeZone before the next step.

And when we want to create the TZDateTime from a DateTime object, we can usually just do like so

var time = tz.TZDateTime.from(
    scheduledNotificationDateTime,
    tz.local,
);

The full implementation is showcased in the example code here: https://github.com/MaikuB/flutter_local_notifications/blob/1fe78b9d129d674cd97cfba49734577b24c56925/flutter_local_notifications/example/lib/main.dart

I have not considered the different edge cases in my very simple work flow so YMMV. Hope this helps! :)



来源:https://stackoverflow.com/questions/64305469/how-to-convert-datetime-to-tzdatetime-in-flutter

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!