I decided to write this post to describe a problem we are dealing with when we are working with production orders through API or when there are users working in different time zones.
Let’s start with a quick introduction. Business Central has two datatypes that can store times – Time and DateTime. What is the main difference, and when to use Time and DateTime? Check this article from Duilio Tacconi: Time (and Data) datatype vs Web Services in SaaS – Dynamics 365 Business Central tales, myths, legends. And something serious. (duiliotacconi.com)
Now, let’s see what we are dealing with in manufacturing and how the logic and rules described by Duilio are not followed in the base app.
Production Orders
What do we have in production orders? In the Production Order Line, we have 6 columns.
- Starting Date
- Starting Time
- Starting Date-Time
- Ending Date
- Ending Time
- Ending Date-Time
field(48; "Starting Date"; Date)
{
Caption = 'Starting Date';
trigger OnValidate()
begin
...
Validate("Starting Time");
end;
}
field(49; "Starting Time"; Time)
{
Caption = 'Starting Time';
trigger OnValidate()
var
ProdOrderLine: Record "Prod. Order Line";
begin
...
CalcProdOrder.Recalculate(Rec, 0, true);
...
UpdateDatetime();
end;
}
field(50; "Ending Date"; Date)
{
Caption = 'Ending Date';
trigger OnValidate()
begin
Validate("Ending Time");
end;
}
field(51; "Ending Time"; Time)
{
Caption = 'Ending Time';
trigger OnValidate()
var
ProdOrderLine: Record "Prod. Order Line";
begin
...
CalcProdOrder.Recalculate(Rec, 1, true);
...
UpdateDatetime();
end;
}
field(198; "Starting Date-Time"; DateTime)
{
Caption = 'Starting Date-Time';
trigger OnValidate()
begin
"Starting Date" := DT2Date("Starting Date-Time");
"Starting Time" := DT2Time("Starting Date-Time");
Validate("Starting Time");
end;
}
field(199; "Ending Date-Time"; DateTime)
{
Caption = 'Ending Date-Time';
trigger OnValidate()
begin
"Ending Date" := DT2Date("Ending Date-Time");
"Ending Time" := DT2Time("Ending Date-Time");
Validate("Ending Time");
end;
}
And that is where the problem starts. If you read Duilio’s post thoroughly, you know that we should always use DateTime datatype if we need to store both date and time. You can say – “But we have date time field and users are changing only the DateTime field”, – and you are right. However, the DateTime fields are just fields used to get the user’s input and are not used for any calculation. When you change the DateTime field, the values are propagated to both the Date and Time fields and all the calculations are done with the Date and Time fields, not with the DateTime field. What does it mean? The calculations are not aware of the original timezone!
What is the impact of having fields without the zone? If you set a starting DateTime in one zone (User A) and then run the recalculation as User B in a different time zone, the system will consider the time configured as a time in your zone, not in the zone of the user who set the time!
Example
Let’s start with the Production Order Line for user A in the UTC timezone. I set the starting DateTime to 09:30 a.m. As you can see, the “Starting Time” was also updated to “9:30 am”.
Now open the production order as User B in the AEST timezone (Australia East). Well, as a user, I would think everything is correct. I can see the correct time, 8:30 PM, as it was configured for 9:30 am UTC = 8:30 pm AEST.
However, if you look at the “Starting Time” field, it still shows 9:30 a.m. and, as the Time datatype does not have any information about the time zone, any calculation will consider the time as AEST for User B. Definitely not what the user would expect.
Now let’s change something in planning (I went to Line -> Routing and updated the setup time from 20 to 30 and back to 20. This means the planning was changed at all).
However, the line was actually changed. See the picture below. Why? Because it used the time from the “Starting Time” 9:30 am as it was a time from the AEST timezone even when it was time originally set in UTC timezone. So, I changed nothing in production planning or configuration, but from the user perspective, the system has completely changed the production order from 8:30 p.m. to 9:30 a.m. Strange, isn’t it?
This can lead to really unexpected problems. Even though it’s not common to have users in different time zones working on production orders for the same location, this is mainly an issue if you want to use API for anything related to production order planning (as Web Services are always in UTC timezone).
One more issue
There is another issue related to time zones in manufacturing – limited capacity for centres. In Manufacturing Setup (and a few other pages), users can configure starting and ending times. This time will be applied to every calculation, so if you have a starting time set to 6 a.m., the system will automatically update the starting time in the production order to 6 am if the user configured anything between 3:45:01 p.m. the previous day to 5:59:59 a.m.
However, these fields are again just Time data type fields without information about the time zone. I agree that it would make no sense to have a DateTime datatype here, but the correct approach would be to have a field that will allow specifying the timezone for which the starting/ending time is configured.
What is the impact? As there is no information about the time zone, all inputs, regardless of the user’s time zone, are evaluated against this field, which means
- 5:00 a.m. UTC will be automatically updated to 6:00 a.m. UTC (users in the AEST timezone will see 5:00 p.m.)
- 5:00 a.m. AEST will be automatically updated to 6:00 a.m. AEST (users in the UTC timezone will see 7:00 p.m.)
Definitely not the correct behaviour.
Conclusion
To be honest, with all these limitations and issues, it is really hard to work with anything in manufacturing through Web Services or when you have users in multiple time zones. If your processes require periodical changes to routings or replanning through web services (for example, from handheld devices as in our project), it is almost impossible to have the correct behaviour.
Do you have experience with this problem? Have you found a suitable solution?