Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wrong selected date #252

Closed
onurays opened this issue Jan 2, 2017 · 19 comments
Closed

Wrong selected date #252

onurays opened this issue Jan 2, 2017 · 19 comments

Comments

@onurays
Copy link

onurays commented Jan 2, 2017

Version: 6.0

screen shot 2017-01-02 at 14 04 27

Selected Date: (Date) $R0 = 2017-01-09 22:00:00 UTC

    func calendar(_ calendar: JTAppleCalendarView, didSelectDate date: Date, cell: JTAppleDayCellView?, cellState: CellState) {
        handleCellTextColor(view: cell, cellState: cellState)
        handleCellSelection(view: cell, cellState: cellState, date: date, isSelectionEvent: true)
    }

Here is my configuration and the problem occurs even if I don't set a timezone.

 func configureCalendar(_ calendar: JTAppleCalendarView) -> ConfigurationParameters {
        var calendar = Calendar.current
        calendar.timeZone = TimeZone(secondsFromGMT: NSTimeZone.local.secondsFromGMT())!
        return ConfigurationParameters(startDate: startDate!, endDate: endDate!, numberOfRows: 6, calendar: calendar, generateInDates: .forAllMonths, generateOutDates: .tillEndOfGrid, firstDayOfWeek: .monday)
 }
@patchthecode
Copy link
Owner

patchthecode commented Jan 2, 2017

By the way, you are using a lot of defaults.
Your caode can be simplified to this

 func configureCalendar(_ calendar: JTAppleCalendarView) -> ConfigurationParameters {
        return ConfigurationParameters(startDate: startDate!, endDate: endDate!)
 }

Let me know if this has resolved your issue.

@onurays
Copy link
Author

onurays commented Jan 2, 2017

Thank you for your quick reply. I will be able to test in 12 hours and will post if it is ok or not.

@onurays
Copy link
Author

onurays commented Jan 3, 2017

Updated to the 6.1.1 and selected date is still wrong... My timeZone is GMT+2.

@nlucky
Copy link

nlucky commented Jan 3, 2017

Version: 5.0.1 has the same problem ,because we need use swift 2.3 ,so can not update to the latest

@patchthecode
Copy link
Owner

patchthecode commented Jan 3, 2017

ok.

@onurays Can I see the following codes?

  1. Your current configureCalendar function code.
  2. The code you are using to print the date on selection
  3. Can you (from the debugger) do a po calendar command to print your NSCalendar instance on the console? Your output should look something like this:
▿ gregorian (fixed)
  - identifier : Foundation.Calendar.Identifier.gregorian
  - kind : "fixed"
  ▿ locale : Optional<Locale>
    ▿ some : en_PH (fixed)
      - identifier : "en_PH"
      - kind : "fixed"
  ▿ timeZone : Asia/Manila (fixed)
    - identifier : "Asia/Manila"
    - kind : "fixed"
    ▿ abbreviation : Optional<String>
      - some : "GMT+8"
    - secondsFromGMT : 28800
    - isDaylightSavingTime : false
  - firstWeekday : 1
  - minimumDaysInFirstWeek : 1

I need this information so that I know how your date is showing up.

@patchthecode
Copy link
Owner

@nlucky let me resolve this on version 6 first. Then i'll port the fix to you.

@nlucky
Copy link

nlucky commented Jan 4, 2017

@patchthecode thanks

@dehlen
Copy link

dehlen commented Jan 4, 2017

I am also experiencing this issue.

1. Configure Calendar Code

func configureCalendar(_ calendar: JTAppleCalendarView) -> ConfigurationParameters {
    let startDate = Date()
    let endDate = Date() + 1.year
    let parameters = ConfigurationParameters(
        startDate: startDate,
        endDate: endDate,
        numberOfRows: 1,
        calendar: Calendar.current,
        generateInDates: .forAllMonths,
        generateOutDates: .off,
        firstDayOfWeek: .monday
    )

    return parameters
}

2. Code to print the date on selection

func calendar(_ calendar: JTAppleCalendarView, didSelectDate date: Date, cell: JTAppleDayCellView?,  cellState: CellState) {
    handleCellSelection(view: cell, cellState: cellState)
    handleCellTextColor(view: cell, cellState: cellState)
    self.habitsViewModel.selectedDate.value = date
    print("\(date)")
}

LLDB Output for po Calendar.current:
(lldb) po Calendar.current
▿ gregorian (current)

  • identifier : Foundation.Calendar.Identifier.gregorian
  • kind : "current"
    ▿ locale : Optional
    ▿ some : en (current)
    • identifier : "en"
    • kind : "current"
      ▿ timeZone : Europe/Berlin (current)
    • identifier : "Europe/Berlin"
    • kind : "current"
      ▿ abbreviation : Optional
      • some : "GMT+1"
    • secondsFromGMT : 3600
    • isDaylightSavingTime : false
  • firstWeekday : 1
  • minimumDaysInFirstWeek : 1

@patchthecode
Copy link
Owner

patchthecode commented Jan 4, 2017

@dehlen I see the issue. I do not believe there is an error. Here are my results.

I made my time zone information to be the same as yours:

▿ gregorian (fixed)
  - identifier : Foundation.Calendar.Identifier.gregorian
  - kind : "fixed"
  ▿ locale : Optional<Locale>
    ▿ some : en (fixed)
      - identifier : "en"
      - kind : "fixed"
  ▿ timeZone : Europe/Berlin (fixed)
    - identifier : "Europe/Berlin"
    - kind : "fixed"
    ▿ abbreviation : Optional<String>
      - some : "GMT+1"
    - secondsFromGMT : 3600
    - isDaylightSavingTime : false
  - firstWeekday : 1
  - minimumDaysInFirstWeek : 1

And i had this code:

func calendar(_ calendar: JTAppleCalendarView, didSelectDate date: Date, cell: JTAppleDayCellView?, cellState: CellState) {
     handleCellSelection(view: cell, cellState: cellState)
     handleCellTextColor(view: cell, cellState: cellState)
     print(date)
     print(formatter.string(from: date))
}

And the results after selecting the 10th were:
screen shot 2017-01-04 at 9 38 10 am

2017-01-09 23:00:00 +0000 // The result of date
2017 01 10                // The result of formatted date

It is important to understand that when you do a print(date) what is happening here is that the print command tries to format that date with its own formatting. This formatting may be different than your timeZone and locale.

In order to print the correct date on console, you need a formatter that is configured with the same timeZone and locale information of your Calendar() instance.

you can do this by:

let formatter = DateFormatter()
formatter.timeZone = Calendar.current.timeZone
formatter.locale = Calendar.current.locale
print(formatter.string(from: date))

This will give you the same date formatted to your time zone rather than what ever default time zone contained in the print command.

Lesson to be learned: printing dates directly on console using the print command can be very deceptive.

I hope this solves your issue?

@patchthecode
Copy link
Owner

@onurays if this also resolves your issue, then feel free to leave a Star Github rating :)
If it does not resolve your issue, then I'll have to do some more digging as to what the problem really is.

@onurays
Copy link
Author

onurays commented Jan 4, 2017

@patchthecode Unfortunately, I had to switch to the FSCalendar (because of the time pressure). I will try to test it again at weekend.

I know, DateFormatter formats correctly. But po or print(date) doesn't. So we have problems if we need operations on Dates, not Strings.

By the way, you already had your star for this beautiful library :)

@patchthecode
Copy link
Owner

patchthecode commented Jan 4, 2017

@onurays but thats the thing. The date is correct. You can do operations on dates and it should work properly. Its only when you use a print command, you have to format it so that it displays correctly on the console.

For instance, put this in your PlayGround:

import UIKit


// ____________________________________________________________________________
// First I create a calendar to match your Calendar.current in Berlin
var myCalendar1 = Calendar(identifier: .gregorian)
myCalendar1.timeZone = TimeZone(identifier: "Europe/Berlin")!
myCalendar1.locale = Locale(identifier: "en")

// Next I create my date formatter
let aFormatter1 = DateFormatter()
aFormatter1.dateFormat = "yyyy MM dd"
aFormatter1.timeZone = myCalendar1.timeZone
aFormatter1.locale = myCalendar1.locale



// Even though theFifth is the 5th, Myplayground is showing it as the 4th. (on the right)
// But date actually IS the fifth. You can operate on it without converting it to strings
let theFifth1 = aFormatter1.date(from: "2017 01 05")

// ____________________________________________________________________________

// This second calendar in my own time zone
var myCalendar2 = Calendar(identifier: .gregorian)
myCalendar2.timeZone = TimeZone(identifier: "America/Vancouver")!
myCalendar2.locale = Locale(identifier: "en_US")

// This is a second formatter in my own time zone
let aFormatter2 = DateFormatter()
aFormatter2.dateFormat = "yyyy MM dd"
aFormatter2.timeZone = myCalendar2.timeZone
aFormatter2.locale = myCalendar2.locale

let theFifth2 = aFormatter2.date(from: "2017 01 05")

Your results should look like this:
screen shot 2017-01-04 at 11 07 57 am

Although they are the same date, they are displayed differently on console. But you do not have to change the dates into string to work with them. You can use them directly.

Your calendar might look perfect with FSCalendar in your timeZone right now, but are you sure it will still be displayed the same way in other regions around the world?

Here are some issues on FSCalendar that has the same problems you are experiencing:

  1. 531
  2. 459
  3. 246
    etc etc etc

In all responses, the answer is the same. Format your date using the correct formatter.
When ever we work with dates, we should always take regions into consideration. Therefore, whether you use FSCalendar, or this library, make sure you format correctly. Cheers 🍻

@dehlen
Copy link

dehlen commented Jan 4, 2017

Yes you have a point. For me it is important to work with the "local date".
So for me this is resolved likes this:

  • The user clicks on the 04.01.2016
  • The date prints 03.01.2016 23:00 which is the correct date in UTC, since i am living in GMT+1
  • In order to further work with the date object representing 03.01.2016 23:00 in GMT+1 i am using the following conversion:
    //date is the object coming from the didSelectDate delegate method
    let dateInRegion = date.inLocalRegion()
    let seconds = dateInRegion.region.timeZone.secondsFromGMT(for: date)
    let localDate = Date(timeInterval: TimeInterval(seconds), since: date)

If i now print localDate I get 2017-01-04 00:00:00 +0000 which is the correct date for me as my app proceeds. The above code snippet makes use of the superb SwiftDate library by the way which makes working with dates a lot easier and more convenient. I am not a contributor or anything for the library I just thought I would mention it if people would try to go with my solution and wonder why it does not work for them.

@patchthecode
Copy link
Owner

patchthecode commented Jan 4, 2017

@dehlen you are exactly correct. I made this library to work with SwiftDate because a number of users requested it. So you can either do the conversion yourself, or you can simply use SwiftDate.

@onurays
Copy link
Author

onurays commented Jan 4, 2017

@patchthecode All right then, thank you for your afford to reproduce the issue. I also see the same issue with other libraries. So (as an Android developer), this is not a problem for me, anymore. I will format the date and not look at the console :) Thanks again.

@patchthecode
Copy link
Owner

@onurays haha. Yea, when it comes to dates, console can really trip you up if youre not formatting it. Cheers.

@AbdHayek
Copy link

I fixed this problem by modifying the time zone in my device calendar like this :
var deviceCalendar = Calendar.current deviceCalendar.timeZone = TimeZone(secondsFromGMT: 0)!

then in JTAppleCalendar ConfigurationParameters returned start date, end date and the previous calendar:
return ConfigurationParameters(startDate: startDate!, endDate: endDate!, calendar : deviceCalendar)

@mudithsilva
Copy link

mudithsilva commented Dec 24, 2018

You can get current Date by using
let localDate = Date(timeInterval: TimeInterval(Calendar.current.timeZone.secondsFromGMT()), since: date)

@Paccos
Copy link

Paccos commented Jul 1, 2020

This may be a dumb/blunt solution but maybe it takes out some of the hassle:

Could those errors be resolved by simply setting the time in the selectedDate property to 12:00 UTC instead of 00:00 UTC ?

Then the selected day should be the same across the globe and since we're dealing with calendar dates, the timestamp shouldn't be relevant.

Or am I thinking the wrong way?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants