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

Fixed Logbook Card/Panel/Dialog Incorrect Entires for input_datetime Entities #9399

Conversation

ShaneQi
Copy link
Contributor

@ShaneQi ShaneQi commented Jun 10, 2021

Proposed change

The issue (in the video, although I changed the input_datetime to different dates, logbook dialog's every entry shows the same date):

Kapture.2021-06-09.at.20.12.20.mp4

The issue under the hood is:
Back in #6978 we added a parameter state to computeStateDisplay in order to compute the display of an explicit state (instead of the entity's current state). But the input_datetime handling wasn't changed properly.
The input_datetime handling should try to format the passed in explicit state if it exists.
This PR added the handling for passed in explicit input_datetime state.

Type of change

  • Dependency upgrade
  • Bugfix (non-breaking change which fixes an issue)
  • New feature (thank you!)
  • Breaking change (fix/feature causing existing functionality to break)
  • Code quality improvements to existing code or addition of tests

Example configuration

N/A

Additional information

Checklist

  • The code change is tested and works locally.
  • There is no commented out code in this PR.
  • Tests have been added to verify that the new code works.

If user exposed functionality or configuration variables are added/changed:

Comment on lines 42 to 46
// When only date is passed to `Date` constructor, it uses UTC regardless of frontend's timezone,
// so we need to add the frontend's timezone offset.
// Other usages of `Date` constructor have both date and time in the string, frontend's timezone is used w/o problem.
const timezoneOffset = new Date().getTimezoneOffset() * 60 * 1000;
const adjustedDateObj = new Date(dateObj.getTime() + timezoneOffset);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

snipaste_20210612_150853

Copy link
Member

@bramkragten bramkragten Jun 15, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Safari does not accept this format for the Date constructor at all, it will return Invalid Date
image

@ShaneQi ShaneQi marked this pull request as ready for review June 12, 2021 20:18
@bramkragten
Copy link
Member

So the issue here is that we don't have the attributes in the logbook?

Comment on lines 73 to 74
const now = new Date();
date = new Date(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of creating a new date, we can just set the hour and minute of now?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is done.

// If trying to display an explicit state, need to parse the explict state to `Date` then format.
// Attributes aren't available, we have to use `state`.
try {
if (!stateObj.attributes.has_time) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If attributes are not available, how can we do this?

try {
if (!stateObj.attributes.has_time) {
// Only has date.
const dateObj = new Date(state);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should make the state string a valid ISO 8601 string, by adding a date or time, then we don't have to struggle with all these issues, and don't have to rely on the current attributes.

@ShaneQi
Copy link
Contributor Author

ShaneQi commented Jun 15, 2021

@bramkragten thanks for taking a look at this PR!


So the issue here is that we don't have the attributes in the logbook?

Yes, we only added icon and state for logbook (back in home-assistant/core#40039), no attributes are sent in the API.


If attributes are not available, how can we do this?

We are getting has_time and has_date from the entity's current attributes.
Because we don't have the event's attributes, I was making the assumption that the entity's has_time and has_date attributes didn't change. That can be wrong, but very rarely to be wrong IMO.
I hope we end up with a solution in which we don't need to make this assumption.


Instead of creating a new date, we can just set the hour and minute of now?

This code exists prior to this PR, I only changed indentation. But yes, I think we can, I can try it.


Safari does not accept this format for the Date constructor at all, it will return Invalid Date
image

The Date constructor doesnt throw on an invalid date.

I think we should make the state string a valid ISO 8601 string, by adding a date or time, then we don't have to struggle with all these issues, and don't have to rely on the current attributes.

To the 3 comments above, I think you are making good points. There seems to be too many issues and hacks when we try to create a Date object from state.

2 questions on this direction:

For making state a ISO 8601 string

Do we make core store the input_datetime's state in ISO 8601? (This sounds to be too big of a breaking change to me)

Or we add logic to core logbook component to process input_datetimes' states into ISO 8601?

Or do we do it on frontend? We would do something like these?:

date and time: 2021-06-03 01:06:00 -> 2021-06-03T01:06:00Z
// split by space, join with `T`, then append `Z`

time only: 16:11:00 -> 2021-06-15T16:11:00Z
// today's ISO 8601 date string + `T` + state + `Z`

date only: 2021-08-07
// this is already ISO 8601

// I think all 3 above need to add timezone offset
// because they are all UTC while the `state` string was generated in the user's timezone

For has_time and has_date attributes

If we don't want to rely on the current attributes, I think the only way is the make core logbook component return them, right?

Or are you thinking about 'looking at state to figure out if it is date or time or both'?

@bramkragten
Copy link
Member

bramkragten commented Jun 15, 2021

Yes, I think the frontend should create a ISO 8601 string.

We don't need to use the has_time and has_date attributes, it can be derived from the state anyway? But I agree that it is an edge case that the current state would have different settings than the historic states. But if we are going to create an ISO string, we need to make sure the state matches those props anyway, otherwise we will get a ton of errors.

About timezone:
If there is a time in an ISO 8601 string, it won't be treated as UTC, just when it is just a date it would be UTC.

@ShaneQi
Copy link
Contributor Author

ShaneQi commented Jun 15, 2021

@bramkragten gotcha, thanks for the advice! I will go with this direction see how it works out.

For timezone: doesn't the letter Z mean UTC? e.g. 2021-06-15T16:11:00Z meaning 16:11:00 UTC (but the state from core 16:11:00 meant to say it's 16:11:00 in the user's timezone therefore we need to add timezone offset).
I might be confused tho right now, will figure it out when I actually debug it.

Thanks again.

@ShaneQi
Copy link
Contributor Author

ShaneQi commented Jun 16, 2021

@bramkragten Finished refactoring to what we discussed.

Let me know if I've misunderstood anything or anything can be improved.
There are lots of ways to convert the state string to IS8601 as well as derive date only/time only/datetime from it. I'm open to any suggestions of changes.

const components = state.split(" ");
if (components.length === 2) {
// Date and time.
const iso8601String = components.join("T") + "Z";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you leave the Z of, you don't need the timezoneOffset

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought Z is required in ISO8601 spec, even after reading some documents, it's still vague.

But I verified it works without Z on both Chrome and Safari, I will remove it. Thanks for the reminder!

// Inserting today's Date string.
const now = new Date();
const dateISO8601String =
now.toISOString().substring(0, 10) + "T" + state + "Z";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here, no need for timezoneOffset when Z is dropped

Comment on lines 52 to 56
const dateObj = new Date(state);
const adjustedDateObj = new Date(
dateObj.getTime() + timezoneOffset
);
return formatDate(adjustedDateObj, locale);
Copy link
Member

@bramkragten bramkragten Jun 17, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will work, but

const dateObj = new Date(`${state}T00:00:00`);

will work too.

// Inserting today's Date string.
const now = new Date();
const dateISO8601String =
now.toISOString().substring(0, 10) + "T" + state + "Z";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
now.toISOString().substring(0, 10) + "T" + state + "Z";
`${now.toISOString().split("T")[0]}T${state};

@ShaneQi
Copy link
Contributor Author

ShaneQi commented Jun 18, 2021

@bramkragten I resolved the last 4 comments. I'm amazed how simple this ended up with, thank you!

@bramkragten bramkragten merged commit db37dff into home-assistant:dev Jun 29, 2021
@bramkragten bramkragten mentioned this pull request Jun 30, 2021
@github-actions github-actions bot locked and limited conversation to collaborators Jun 30, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Logbook Card/Panel/Dialog Incorrect Entires Texts for input_datetime Entities
3 participants