全日历跨时区添加事件

时间:2019-03-01 04:40:33

标签: php jquery datetime timezone fullcalendar

很明显,我缺少在FullCalendar中创建事件的完全根本的东西,因此,看看是否有人有解决方案或建议。

目标:具有日历功能,辅导员可以使用该功能让客户知道他们的开放时间(时间不是全天,可以短至一小时)。

顾问和客户不一定要处于同一时区,因此必须以反映各个时区的适当时间的方式来创建事件。

例如,一名辅导员(在新西兰)创建了一个可用活动,始于:

Friday, 1 March 2019 at 7:00:00 a.m.

纽约的客户应将该事件视为:

Thursday, 28 February 2019 at 1:00:00 p.m

这是我在努力实现的目标,不确定使用FullCalendar能否实现

在创建事件时,“时区”选项似乎没有任何区别(是的,我完全接受我可能做的事情完全错误)。

在这个calendar小提琴中,我将时区设置如下:

$('#calendar').fullCalendar({
    header: {
      left: 'prev,next today',
      center: 'title',
      right: 'month,agendaWeek,agendaDay'
    },
    timezone: 'Pacific/Auckland'
    ....
});

当我在2019年3月1日上午7点选择FullCalendar时,其开始日期为UTC:

Fri Mar 01 2019 07:00:00 GMT+0000

如果我使用moment.tz将开始日期格式化为太平洋/奥克兰:

console.log(moment.tz(startDate, 'Pacific/Auckland').format());

我得到:

2019-03-01T20:00:00+13:00

这是对原始开始日期的正确转换,但显然在这种情况下没有用,因为它不是预期的日期。

如果我将事件拖放到2019年3月1日上午7点(请参阅相同的fiddle),然后单击它以使用以下命令将事件对象写到控制台:

eventClick: function(event, element) 
{
    console.log("event: ");
    console.log(event);
},

显示以下内容(为简单起见,在此缩短):

    "_fc3"
    _start 
    Fri Mar 01 2019 07:00:00 GMT+0000 {...}
    _a
    [2019, 2, 1, 4 more...]
    _ambigTime
    false
    _ambigZone
    true
   _d
   Fri Mar 01 2019 20:00:00 GMT+1300 (New Zealand Daylight Time) {}

所以 _start 是星期五2019年3月1日格林尼治标准时间+0000-它(现在忽略偏移量)是应该的时间(例如,应该是上午7点)

_d 是2019年3月1日星期五格林尼治标准时间+1300(新西兰夏令时间)。

但是我显然不能保存 _d 的值,因为在这种情况下显然不是期望的时间。

此外,如果我将_start日期原样保存到MySQL datetime字段中,它将存储为“ 2019-03-01 07:00:00”(MySQL服务器设置为UTC),并且如果导入了它日历中显示为2019年3月1日上午7点,并且不考虑用户时区。

我一如既往地检查了可能的答案,但似乎没有答案可以解决这个问题。

正如我所说,我希望我只是缺少一些基本知识。

任何建议将不胜感激。

编辑:更新小提琴

EDIT (添加图片和说明)

fiddle中(如本图所示):

image of fiddle

  1. 将其拖到上午7点(例如)
  2. 单击事件以访问事件对象
  3. 这显示的时间是4.以UTC / GMT时间
  4. 这显示了6点中以UTC / GMT表示的时间
  5. 这显示的是新西兰时区(对于我来说就像在新西兰一样)在8月的时间。

所以我想我在这里缺少的是如何获取公共启动属性

我正在寻找/期望的开始时间是:

Sat Mar 02 2019 07:00:00 GMT+1300 (New Zealand Daylight Time)

这是UTC时间:

Friday, 1 March 2019 at 6:00:00 p.m. UTC

因此,UTC星期五时间正是我希望保存在数据库中的时间。

注意:我实际上在新西兰,因此该时区以外的人的提琴会有所不同。

1 个答案:

答案 0 :(得分:0)

我通过将所有日期时间存储在UTC中来完成类似的项目。这样,很容易显示任何时区的时间。

我已经实现了以下目标: 1.我创建了一个下拉列表以选择时区。 2.初始化页面上的全日历 3.使用moment.js猜测用户的时区。 4.将日历时区转换为UTC 5. Ajax使用UTC时间保存删除的事件 6.呈现事件时,从下拉列表中显示默认时区,否则显示用户选择的时区。

  let calendar = $("#calendar").fullCalendar({
        defaultView: "agendaWeek",
        header: {
            left: "prev,next today",
            center: "title",
            right: "month,agendaWeek,agendaDay"
        },
        now: moment().format("Y-MM-DD HH:mm:ss"),
        height: "auto",
        slotDuration: "00:30:00",
        defaultTimedEventDuration: "00:30:00",
        timezone: "local",
        weekends: false,
        dragRevertDuration: 0,
        allDaySlot: false,
        slotEventOverlap: false,
        editable: true,
        eventStartEditable: true,
        eventDurationEditable: true,
        droppable: true,
        eventSources: [
            fcSources.loadEvents,
            fcSources.loadEwsEvents
        ],
        businessHours: [ // highlight working hours
            {
                dow: [ 1, 2, 3, 4, 5], // weekdays
                start: '08:00',
                end: '18:00'
            }
        ],
        drop: function (date) {
            //Call when you drop slot for the first time
            let defaultDuration = moment.duration($("#calendar").fullCalendar("option", "defaultTimedEventDuration"));
            $("input[name='EVENTS[ID]']").val(null);
            $("input[name='EVENTS[TITLE]']").val($(this).data().event.title);
            $("input[name='EVENTS[EVENT_START]']").val($(this).convertTimeToUTC(date));
            $("input[name='EVENTS[EVENT_END]']").val($(this).convertTimeToUTC(date.clone().add(defaultDuration)));
            $(this).addCalendarEvent();
        },
        eventOverlap: function (stillEvent, movingEvent) {
            return stillEvent.allDay && movingEvent.allDay;
        },
        eventDrop: function (event) {
                $("input[name='EVENTS[ID]']").val(event.id);
                $("input[name='EVENTS[TITLE]']").val(event.title);
                $("input[name='EVENTS[EVENT_START]']").val($(this).convertTimeToUTC(event.start));
                $("input[name='EVENTS[EVENT_END]']").val($(this).convertTimeToUTC(event.end));
            //if the call is confirmed or complete then do not move it
                if ($.trim(event.status) !== "COMPLETE" && $.trim(event.status) !== "CONFIRMED") {
                    $(this).updateCalendarEvent();
                }
        }
    });

//然后选择下拉列表

  //self initialising function for timezones dropdown
    (function(window, document, $, undefined){
        const _t = (s) => {
            if (i18n !== void 0 && i18n[s]) {
                return i18n[s];
            }
            return s;
        };
        const timezones = [
            "Etc/GMT+12",
            "Pacific/Midway",
            "Pacific/Honolulu",
            "America/Juneau",
            "America/Dawson",
            "America/Boise",
            "America/Chihuahua",
            "America/Phoenix",
            "America/Chicago",
            "America/Regina",
            "America/Mexico_City",
            "America/Belize",
            "America/Detroit",
            "America/Indiana/Indianapolis",
            "America/Bogota",
            "America/Glace_Bay",
            "America/Caracas",
            "America/Santiago",
            "America/St_Johns",
            "America/Sao_Paulo",
            "America/Argentina/Buenos_Aires",
            "America/Godthab",
            "Etc/GMT+2",
            "Atlantic/Azores",
            "Atlantic/Cape_Verde",
            "GMT",
            "Africa/Casablanca",
            "Atlantic/Canary",
            "Europe/Belgrade",
            "Europe/Sarajevo",
            "Europe/Brussels",
            "Europe/Amsterdam",
            "Africa/Algiers",
            "Europe/Bucharest",
            "Africa/Cairo",
            "Europe/London",
            "Europe/Helsinki",
            "Europe/Athens",
            "Asia/Jerusalem",
            "Africa/Harare",
            "Europe/Moscow",
            "Asia/Kuwait",
            "Africa/Nairobi",
            "Asia/Baghdad",
            "Asia/Tehran",
            "Asia/Dubai",
            "Asia/Baku",
            "Asia/Kabul",
            "Asia/Yekaterinburg",
            "Asia/Karachi",
            "Asia/Kolkata",
            "Asia/Kathmandu",
            "Asia/Dhaka",
            "Asia/Colombo",
            "Asia/Almaty",
            "Asia/Rangoon",
            "Asia/Bangkok",
            "Asia/Krasnoyarsk",
            "Asia/Shanghai",
            "Asia/Kuala_Lumpur",
            "Asia/Taipei",
            "Australia/Perth",
            "Asia/Irkutsk",
            "Asia/Seoul",
            "Asia/Tokyo",
            "Asia/Yakutsk",
            "Australia/Darwin",
            "Australia/Adelaide",
            "Australia/Sydney",
            "Australia/Brisbane",
            "Australia/Hobart",
            "Asia/Vladivostok",
            "Pacific/Guam",
            "Asia/Magadan",
            "Pacific/Fiji",
            "Pacific/Auckland",
            "Pacific/Tongatapu"
        ];
        const i18n = {
            "Etc/GMT+12": "International Date Line West",
            "Pacific/Midway": "Midway Island, Samoa",
            "Pacific/Honolulu": "Hawaii",
            "America/Juneau": "Alaska",
            "America/Dawson": "Pacific Time (US and Canada); Tijuana",
            "America/Boise": "Mountain Time (US and Canada)",
            "America/Chihuahua": "Chihuahua, La Paz, Mazatlan",
            "America/Phoenix": "Arizona",
            "America/Chicago": "Central Time (US and Canada)",
            "America/Regina": "Saskatchewan",
            "America/Mexico_City": "Guadalajara, Mexico City, Monterrey",
            "America/Belize": "Central America",
            "America/Detroit": "Eastern Time (US and Canada)",
            "America/Indiana/Indianapolis": "Indiana (East)",
            "America/Bogota": "Bogota, Lima, Quito",
            "America/Glace_Bay": "Atlantic Time (Canada)",
            "America/Caracas": "Caracas, La Paz",
            "America/Santiago": "Santiago",
            "America/St_Johns": "Newfoundland and Labrador",
            "America/Sao_Paulo": "Brasilia",
            "America/Argentina/Buenos_Aires": "Buenos Aires, Georgetown",
            "America/Godthab": "Greenland",
            "Etc/GMT+2": "Mid-Atlantic",
            "Atlantic/Azores": "Azores",
            "Atlantic/Cape_Verde": "Cape Verde Islands",
            "Europe/London": "Dublin, Edinburgh, Lisbon, London",
            "Africa/Casablanca": "Casablanca, Monrovia",
            "Atlantic/Canary": "Canary Islands",
            "Europe/Belgrade": "Belgrade, Bratislava, Budapest, Ljubljana, Prague",
            "Europe/Sarajevo": "Sarajevo, Skopje, Warsaw, Zagreb",
            "Europe/Brussels": "Brussels, Copenhagen, Madrid, Paris",
            "Europe/Amsterdam": "Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna",
            "Africa/Algiers": "West Central Africa",
            "Europe/Bucharest": "Bucharest",
            "Africa/Cairo": "Cairo",
            "Europe/Helsinki": "Helsinki, Kiev, Riga, Sofia, Tallinn, Vilnius",
            "Europe/Athens": "Athens, Istanbul, Minsk",
            "Asia/Jerusalem": "Jerusalem",
            "Africa/Harare": "Harare, Pretoria",
            "Europe/Moscow": "Moscow, St. Petersburg, Volgograd",
            "Asia/Kuwait": "Kuwait, Riyadh",
            "Africa/Nairobi": "Nairobi",
            "Asia/Baghdad": "Baghdad",
            "Asia/Tehran": "Tehran",
            "Asia/Dubai": "Abu Dhabi, Muscat",
            "Asia/Baku": "Baku, Tbilisi, Yerevan",
            "Asia/Kabul": "Kabul",
            "Asia/Yekaterinburg": "Ekaterinburg",
            "Asia/Karachi": "Islamabad, Karachi, Tashkent",
            "Asia/Kolkata": "Chennai, Kolkata, Mumbai, New Delhi",
            "Asia/Kathmandu": "Kathmandu",
            "Asia/Dhaka": "Astana, Dhaka",
            "Asia/Colombo": "Sri Jayawardenepura",
            "Asia/Almaty": "Almaty, Novosibirsk",
            "Asia/Rangoon": "Yangon Rangoon",
            "Asia/Bangkok": "Bangkok, Hanoi, Jakarta",
            "Asia/Krasnoyarsk": "Krasnoyarsk",
            "Asia/Shanghai": "Beijing, Chongqing, Hong Kong SAR, Urumqi",
            "Asia/Kuala_Lumpur": "Kuala Lumpur, Singapore",
            "Asia/Taipei": "Taipei",
            "Australia/Perth": "Perth",
            "Asia/Irkutsk": "Irkutsk, Ulaanbaatar",
            "Asia/Seoul": "Seoul",
            "Asia/Tokyo": "Osaka, Sapporo, Tokyo",
            "Asia/Yakutsk": "Yakutsk",
            "Australia/Darwin": "Darwin",
            "Australia/Adelaide": "Adelaide",
            "Australia/Sydney": "Canberra, Melbourne, Sydney",
            "Australia/Brisbane": "Brisbane",
            "Australia/Hobart": "Hobart",
            "Asia/Vladivostok": "Vladivostok",
            "Pacific/Guam": "Guam, Port Moresby",
            "Asia/Magadan": "Magadan, Solomon Islands, New Caledonia",
            "Pacific/Fiji": "Fiji Islands, Kamchatka, Marshall Islands",
            "Pacific/Auckland": "Auckland, Wellington",
            "Pacific/Tongatapu": "Nuku'alofa"
        };
        //get current time
        const dateTimeUtc = moment().utc();
        document.querySelector(".js-TimeUtc").innerHTML = dateTimeUtc.format("ddd, DD MMM YYYY HH:mm:ss");
        const dateTimeLocal = moment().utc(moment.tz.guess());
        document.querySelector(".js-TimeLocal").innerHTML = dateTimeLocal.format("ddd, DD MMM YYYY HH:mm:ss");
        const selectorOptions = moment.tz.names()
            .filter(tz => {
                return timezones.includes(tz)
            })
            .reduce((memo, tz) => {
                memo.push({
                    name: tz,
                    offset: moment.tz(tz).utcOffset()
                });

                return memo;
            }, [])
            .sort((a, b) => {
                return a.offset - b.offset
            })
            .reduce((memo, tz) => {
                const timezone = tz.offset ? moment.tz(tz.name).format('Z') : '';
                return memo.concat(`<option value="${tz.name}">${_t(tz.name)}</option>`);
            }, "");

        document.querySelector(".js-Selector").innerHTML = selectorOptions;

        $(".js-Selector").on("change", e => {
            const timestamp = dateTimeUtc.unix();
            const offset = moment.tz(e.target.value).utcOffset() * 60;
            const dateTimeSelected = moment.unix(timestamp + offset).utc();
            document.querySelector(".js-TimeSelected").innerHTML = dateTimeSelected.format("ddd, DD MMM YYYY HH:mm:ss");
            timeZone = $(".js-Selector").val();
            if(timeZone !=  moment.tz.guess()) {
                let timezoneWarningMessage = '<div class="alert alert-warning timezone-warning" role="alert" class="btn btn-indigo btn-sm ml-0 waves-effect waves-light bg-warning timezone-warning">' +
                    'Your timezone has been changed to <b>' + timeZone + '</b></div>';

                if($(".timezone-warning").length > 0) {
                    $(".timezone-warning").replaceWith(timezoneWarningMessage);
                } else {
                    $(".fc-view-container").prepend(timezoneWarningMessage);
                }
            } else {
                $(".timezone-warning").replaceWith('');
            }
            $('#calendar').fullCalendar('option', 'timezone', $(".js-Selector").val() || false);
        });

        document.querySelector(".js-Selector").value = "Europe/London";
        const event = new Event("change");
        document.querySelector(".js-Selector").dispatchEvent(event);
        $(".js-Selector").chosen();
    })(window, document, jQuery);

//现在将所选时区传递给事件源

     let loadEvents: {
                url: "", //your url,
                type: "GET",
                cache: true,
                dataType: "json",
                success: function (data) {
                    //based on the dropdown changetimezone of each event 

                    let updatedTime = [];
                    $.each(data.events, function( k, v ) {
                        v.start = moment.tz(v.start, timeZone);
                        v.end = moment.tz(v.end, timeZone);
                        updatedTime[k] = v ;
                    });
                    return updatedTime;
                }
            }

 //function to convert fullcalendar time to utc
    $.fn.convertTimeToUTC = function (convertTime) {
       if($(this).isObject(convertTime)) {
            return moment.tz(convertTime.format("Y-MM-DD HH:mm:ss"), moment.tz.guess()).utc().format("Y-MM-DD HH:mm:ss");
        }
    };
    // Returns if a value is an object
    $.fn.isObject =  function(value) {
        return value && typeof value === 'object';
    };