PropertyDrawer for DateTime class not getting called.

I was hoping to add a property drawer for System DateTime and TimeSpan but I can’t seem to even get the OnGUI method to get called. Is there some requirement for property drawers that I’ve missed. DateTime is serializable, but this shell code isn’t getting called for me. It does work for a class I made myself. Is there a restriction on the namespace or the declaring assembly I’ve missed.

Mike

[CustomPropertyDrawer(typeof(DateTime))]
public class DateTimeDrawer : PropertyDrawer
{

// Draw the property inside the given rect
override public void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
Debug.Log(“Drawing DateTime”);

// Using BeginProperty / EndProperty on the parent property means that
// prefab override logic works on the entire property.
EditorGUI.BeginProperty(position, label, property);

// Draw label
position = EditorGUI.PrefixLabel(position, GUIUtility.GetControlID(FocusType.Passive), label);

EditorGUI.EndProperty();
}
}

Unity can’t serialize DateTime at all, and Property Drawers hang off the serialization functionality.

1 Like

Thanks. I accept the explanation, but I question why Unity can’t serialize it. Is there an interface or implicit cast I can implement to help it along. DateTime is a serializable class, and a rather simple one.

Date time has no serializable fields, it’s all properties.
Try storing the values in some variables and use ISerializationCallbackReceiver to convert between.

1 Like

Maybe I don’t have an understanding of what .Net thinks is serializable and what Unity thinks is serializable. Wrapping the DateTime class seems like this answer. I just hate duplicating the representation of data because then you have to worry about keeping them in sync.

This is the approach I’m working on, is it what you’d suggest? The public dateTime field is available for scripts to access. The private_dateTime field is editable from the inspector and the ISerializationCallbackReceiver methods do the conversions. (They are getting called every frame in the inspector, whether the string changes or not. Is that correct?)

[Serializable]
public class UDateTime: ISerializationCallbackReceiver
{
public DateTime dateTime;

[SerializeField]
private string _dateTime;

public static implicit operator DateTime( UDateTime udt )
{
return (udt.dateTime);
}

public static implicit operator UDateTime( DateTime dt )
{
return new UDateTime() { dateTime = dt };
}

public void OnAfterDeserialize()
{
DateTime.TryParse(_dateTime, out dateTime);
}

public void OnBeforeSerialize()
{
_dateTime = dateTime.ToString();
}
}

2 Likes

Hey @mikewarren !

What a funny coincidence! Earlier this week you helped me out here: How to resolve script references in scene bundles from dynamically loaded assemblies? - Questions & Answers - Unity Discussions and now I was searching for a DateTime property drawer and stumbled upon this thread of yours! Maybe you can already tell me what I’ll be up to next? :wink: And thanks again for helping me out!

Concerning your question, I indeed do think that was what karl_jones was getting at. Now, you can write a property drawer which makes use of your _dateTime variable. The property drawer still can’t access your DateTime “dateTime” variable because it’s not serializable but at least your code will be able to.

And concerning the access modifier of private string _dateTime, even though it’s private, the property drawer can access it. I wrote a simple property drawer to test it out myself. It’s very simple and looks like this:

[CustomPropertyDrawer(typeof(UDateTime))]
  public class UDateTimeDrawer : PropertyDrawer
  {
    public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
    {
      EditorGUI.BeginProperty(position, label, property);
      EditorGUI.PropertyField(rectDateTime, property.FindPropertyRelative("_dateTime"), new GUIContent("DateTime"));
      EditorGUI.EndProperty();
    }
  }

I played around a few hours, trying a more elegant solution but to no avail. It seems like it’s just kind of a pain to work with property drawers. I figure, if I have to do something slightly more complex again, I might work with custom inspectors. Especially because there you can at least really access the data type you’re dealing with.

Also, I made some small modifications and additions so I can configure the desired format of the DateTime in the editor. I’ll gladly post it if your interested, although it’s really simple. And at least the property drawer part is kind of a hack with some magic numbers used for the GUI spacing.

No problem. Glad I could help. Most of the time, I feel like I don’t have a clue what I’m doing.

The small code segment I posted seems to be the simplest answer. You don’t need the property drawer as long as you’re happy with the way the inspector renders it. I was finding myself with lots of scripts that needed time references and that were duplicating code to convert to/from string representations. I wanted one class that I could reuse that would work with Unity. The implicit conversion methods make it work almost seamlessly with most DateTime methods.

I’d still prefer a better serialization system in Unity, but I appreciate that it’s a complicated issue, so it’s hard to be too critical. Appreciate the advice.

Sorry to necroing :frowning:
I’ve found that the only thing on the internet is using ODIN plugin or UDateTime from EntranceJew, but this requires to change all DateTimes to UDateTimes, which is not what I’m looking for :frowning:

According to what I have read, the impediment relies on the fact that all of DateTime info is only accessible by properties, isn’t it? But DateTime class implements ISerializable, so I think should be feasible to get that info and serialize to an Editor property drawer…but I don’t really know how, anyone after 5 years have gone farther?

@L0tan yes you are right. btw you can read serialization rules here: Unity - Manual: Script serialization
But yeah, DateTime exposes only properties, while the field, that contains all the date information without kind, its stored as private ulong dateData;
So, even if DateTime is maked with [SerializableAttribute], unity cant serialize it because theres not a single serializable field (field that unity can see, check the rules).
So, if you create a property drawer for typeof(DateTime), its never gonna be called :confused: