IEnumerator DelayAction(TimeSpan dueTime, Action action, ICancelable cancellation)
            {
#if UNITY_EDITOR
                if (!ScenePlaybackDetector.IsPlaying)
                {
                    var startTime = DateTimeOffset.UtcNow;
                    while (true)
                    {
                        yield return(null);

                        if (cancellation.IsDisposed)
                        {
                            break;
                        }

                        var elapsed = DateTimeOffset.UtcNow - startTime;
                        if (elapsed >= dueTime)
                        {
                            UnityMainThreadDispatcher.UnsafeSend(action);
                            break;
                        }
                    }
                    ;
                    yield break;
                }
#endif

                if (dueTime == TimeSpan.Zero)
                {
                    yield return(null);

                    if (cancellation.IsDisposed)
                    {
                        yield break;
                    }

                    UnityMainThreadDispatcher.UnsafeSend(action);
                }
                else
                {
                    var startTime = Time.realtimeSinceStartup; // this is difference
                    var dt        = (float)dueTime.TotalSeconds;
                    while (true)
                    {
                        yield return(null);

                        if (cancellation.IsDisposed)
                        {
                            break;
                        }

                        var elapsed = Time.realtimeSinceStartup - startTime;
                        if (elapsed >= dt)
                        {
                            UnityMainThreadDispatcher.UnsafeSend(action);
                            break;
                        }
                    }
                }
            }
            // delay action is run in StartCoroutine
            // Okay to action run synchronous and guaranteed run on MainThread
            IEnumerator DelayAction(TimeSpan dueTime, Action action, ICancelable cancellation)
            {
#if UNITY_EDITOR
                if (!ScenePlaybackDetector.IsPlaying)
                {
                    var startTime = DateTimeOffset.UtcNow;
                    while (true)
                    {
                        yield return(null);

                        if (cancellation.IsDisposed)
                        {
                            break;
                        }

                        var elapsed = DateTimeOffset.UtcNow - startTime;
                        if (elapsed >= dueTime)
                        {
                            UnityMainThreadDispatcher.UnsafeSend(action);
                            break;
                        }
                    }
                    ;
                    yield break;
                }
#endif

                if (dueTime == TimeSpan.Zero)
                {
                    yield return(null); // not immediately, run next frame

                    if (cancellation.IsDisposed)
                    {
                        yield break;
                    }

                    UnityMainThreadDispatcher.UnsafeSend(action);
                }
                else if (dueTime.TotalMilliseconds % 1000 == 0)
                {
                    yield return(new WaitForSeconds((float)dueTime.TotalSeconds));

                    if (cancellation.IsDisposed)
                    {
                        yield break;
                    }

                    UnityMainThreadDispatcher.UnsafeSend(action);
                }
                else
                {
                    var startTime = Time.time;
                    var dt        = (float)dueTime.TotalSeconds;
                    while (true)
                    {
                        yield return(null);

                        if (cancellation.IsDisposed)
                        {
                            break;
                        }

                        var elapsed = Time.time - startTime;
                        if (elapsed >= dt)
                        {
                            UnityMainThreadDispatcher.UnsafeSend(action);
                            break;
                        }
                    }
                }
            }