0

I'm building a weekly picker. For the most part it works as intended, I actually get the right week when I click on it, but the selected days within the calendar portion of the picker are displaying a day behind. For example, in the screenshot below, the week picked is 2020-06-08 to 2020-06-14 yyyy-mm-dd format by the way. But as you can see in the picker, it displays the week shifted - 1

I'll post the relevant code but hard as I tried, I couldn't make a codesandbox for you. Way too many dependencies

Notice the days in the labels and the days in the picker

Here is the convertDate function for the formatting. This is not related to the problem but in case you're wondering what was in it from the main function

const convertDate = (date) => {
  let dt = new Date(date);
  var yyyy = dt.getFullYear();
  var mm = dt.getMonth() + 1; // getMonth() is zero-based
  var dd = dt.getDate();

  return `${yyyy}-${(mm > 9 ? '' : '0') + mm}-${(dd > 9 ? '' : '0') + dd}`;
};

And this the actual function that renders the days in the picker

EDIT (with help from Sergei

const handleClick = (e) => {
  setDate(new Date(date.setDate(e.target.id)));
  
  // added this to calculate the offset to my local timezone
  let localDate = new Date(date.setDate(e.target.id));
  var localoffset = new Date().getTimezoneOffset();
  var timeZoneFromDB = -4.00;
  var tzDifference = timeZoneFromDB * localoffset + localDate.getTimezoneOffset();
  var offsetTime = new Date(localDate.getTime() + tzDifference * localoffset * 1000);

  const firstDay = new Date(
    offsetTime.setDate(offsetTime.getDate() - offsetTime.getDay() + 1)
  );
  const lastDay = new Date(
    offsetTime.setDate(offsetTime.getDate() - offsetTime.getDay() + 7)
  );

  setWeek({ firstDay, lastDay });

  const value = e.target.value;
  setState({
    ...state, 
    [e.target.name]: value,
    startdate: convertDate(firstDay), 
    enddate: convertDate(lastDay)
  }) 
};

const renderDays = () => {
  let month = date.getMonth() + 1;
  let ar = [];
  for (let i = 1; i <= days[month]; i++) {
    let currentDate = new Date(date).setDate(i);

    let cName = "single-number ";
    if (
      new Date(state.startdate).getTime() <= new Date(currentDate).getTime() &&
      new Date(currentDate).getTime() <= new Date(state.enddate).getTime() 
    ) {
      cName = cName + "selected-week";4

      console.clear();
      console.log(new Date().getTimezoneOffset());
      console.log("start date: ", new Date(state.startdate).getTime());
      console.log("converted start date: ", convertDate(new Date(state.startdate).getTime()));
      console.log("current date: ", new Date(currentDate).getTime());
      console.log("converted current date: ", convertDate(new Date(currentDate).getTime()));
      console.log("end date: ", new Date(state.enddate).getTime());
      console.log("converted end date: ", convertDate(new Date(state.enddate).getTime()));

    }

    ar.push(
      <div key={v4()} id={i} className={cName} onClick={handleClick}>
        {i}
      </div>
    );
  }

  const displayDate = new Date(date).setDate(1);
  let dayInTheWeek = new Date(displayDate).getDay();

  let empty = [];
  for (let i = 1; i < dayInTheWeek; i++) {
    empty.push(<div key={v4()} id={i} className="single-number empty"></div>);
  }

  return [...empty, ...ar];
};

Here's a pic of what I am console.logging so you can see that I am capturing the intended dates (ignore the undefined). This is the state being console logged in the useEffect() But also check out the individual logs from within the renderDays(). They're a day behind

enter image description here

I just need the days in the picker to + 1 in the view Thanks in advanced you for your help

LOTUSMS
  • 10,317
  • 15
  • 71
  • 140
  • I tried to reproduce (and simplify a bit) your issue, but im not able to reproduce it as is, without seeing `handleClick` probably,, Question is how your `date` object is set. Now why: because `1591574400000` that you see in console will be 2020-06-08 `00:00` for GMT and for any UTC > 0, but if your timezone is negative - you will get what you see. Methods like `dt.getFullYear()` and `getMonth` and `getDate` returns values using your OS `local time`. [sandbox](https://codesandbox.io/s/flamboyant-andras-wlhtti?file=/src/App.js:888-895) – Sergey Sosunov Aug 25 '22 at 16:29
  • Ah that makes so much sense. Is there ant workaround to generalize it to negative timezones only? This is going to be used in the USA only – LOTUSMS Aug 25 '22 at 17:49
  • @SergeySosunov I added the handleCLick function for clarity – LOTUSMS Aug 25 '22 at 17:52
  • [Please do not upload images of code/data/errors when asking a question.](//meta.stackoverflow.com/q/285551) – Heretic Monkey Aug 25 '22 at 18:28
  • 1
    Be very careful of using `new Date(string)` to parse date values; [it rarely ends well](https://stackoverflow.com/questions/2587345/why-does-date-parse-give-incorrect-results). – Heretic Monkey Aug 25 '22 at 18:30
  • How do I show the console log without running code? – LOTUSMS Aug 25 '22 at 18:32
  • 1
    I got it working with a tiny issue that will most likely not get caught in testing lol I'll take my chances lol. Thanks guys. I credited you both – LOTUSMS Aug 25 '22 at 19:02

1 Answers1

1

With the help of Sergei and Heretic in the comments I was able to get it to work by adding the following helper function outside of the main view object

function addDays(date, days) {
   var result = new Date(date);
   result.setDate(result.getDate() + days);
   return result;
}

Then I updated my render function to conditionally check this way

let currentTime = new Date(currentDate).getTime()
let startdayinview = new Date(state.startdate).getTime()
let enddayinview = new Date(state.enddate).getTime()

if (
  addDays(startdayinview, -1) <= addDays(currentTime, -2) &&
  addDays(currentTime, 0) <= addDays(enddayinview, 1) 
) {
  cName = cName + "selected-week";
}

As Heretic mentioned, the Date object is not ideal, but we gotta work with what we're given!

LOTUSMS
  • 10,317
  • 15
  • 71
  • 140