В макросе пробежаться циклом по значениям времени

Автор Олег*, 17.04.2013, 01:08

« назад - далее »

Олег*

Возникла задача в макросе пробежаться циклом по значениям времени с определенным шагом.
Первое, что пришло в голову,  сделать это приблизительно вот так:

For Время = CSng(TimeValue("10:00")) To CSng(TimeValue("15:00")) Step CSng(TimeValue("01:00"))

Но это как-то громоздко очень. А нельзя ли как-нибудь сделать то же самое иначе, поудобнее, поизящнее?

Простенький пример прилагаю.
Муж это единственный зарегенный юзер, а все остальные это хакеры :)

Serge 007

Бесплатная помощь: www.excelworld.ru
Платная помощь: sergeyizotov@excelworld.ru
Ю-money: 41001419691823 | WMR:126292472390

Олег*

Цитата: Serge 007 от 17.04.2013, 07:13
...
Dim Время As Date
...
For Время = "10:00" To "15:00" Step 1 / 24
...


Спасибо!
Чёта я ступил. Забыл про существование типа даных Date и стал изобретать велосипед собственной конструкции :)
Растренерованность сказывается.
Я ж говорю,  у меня  обычно по жизни очень долго нет необходимости "лезть в мотор" своих Эксельных программ и я "катаюсь" на них совсем как обычный пользователь. Причем это время может длиться до полугода.

Потом бац, приходит мысля... А не попробовать ли мне смастерить такую вот штуку. Ну и начинаю все почти с самого нуля, поскольку за полгода все уже изрядно подзабылось.

Тут недавно до прикола дело дошло. Надо было, чтобы оператор макроса ссылался на другой лист. Ну и я пишу:

"Лист5".Range("A1:C8").ClearContents

Эксель ругается, а я не пойму, чего он ругается-то. Я же вроде все ему объяснил, лист такой-то, рендж такой-то. Чего тебе еще надо-то?! :)
Делай чего просят :)

Сижу и думаю, чего не хватает...
В книжку заглянул и понял, что не хватает сущего пустяка - Worksheets.

Растренерованность :(







Муж это единственный зарегенный юзер, а все остальные это хакеры :)

Олег*

А еще вот такой вопрос...

У меня сейчас код записан вот так:

    For Время = "10:00" To "11:00" Step "00:15"
   
        If Время = "10:30" Then Exit For


и я ожидаю, что в цикле будут проанализированы значения времени (с шагом 15 минут), начиная с 10:00 до 11:00 включительно, и при этом значение 10:30 будет пропущено.

А в результате получаю (см. приложенный файл time_02.xls):



№   Время
1   10:00
2   10:15
3   10:30
4   10:45

Т.е. все наоборот! :)
11:00 нет, а 10:30 есть :(

Кстати, это та самая проблема, которая заставила меня создать эту ветку. В прошлом "велосипедном" :)  варианте она тоже присутствовала.

Там я ее решал прибавлением одной секунды к конечному значению цикла и созданием некоторого "буфера" вокруг исключаемого из цикла значения, т.е.

    For Время = Csgl(TimeValue("10:00")) To Csgl(TimeValue("11:00")) + Csgl(TimeValue("00:00:01"))  Step Csgl(TimeValue("00:15"))
   
                   If Время > Csgl(TimeValue("10:29:59"))   And   Csgl(TimeValue(Время < "10:30:01"))  Then Exit For


Я, конечно, понимаю, почему так происходит.
Там дробные значения с определенной точностью и нет точного совпадения. Поэтому приходится создавать вокруг значения "10:45" некий буфер, чтобы Эксель понял, что если значение попало в этот интервал, его надо пропустить.

И то же самое с конечным значением цикла. Экселю не хватает какой-то малюсенькой дробной частички, чтобы понять, что значение "11:00" тоже надо анализировать.

Вопрос такой:
я эту проблему решил очень сложно и, честно говоря, мне это совсем не нравится.

А можно сделать как-нибудь иначе, попроще и полаконичнее?

Муж это единственный зарегенный юзер, а все остальные это хакеры :)

_Boroda_

Олег, По поводу листов - специально ради Вас  :) создал темку-опрос. Если хотите - подождите ответов, если загорелось срочно - пишите в личку, отвечу там.
Скажи мне, кудесник, любимец ба'гов...



Яндекс-деньги: 41001632713405
Webmoney: R289877159277; Z102172301748; E177867141995

Олег*

Цитата: _Boroda_ от 17.04.2013, 11:34
Олег, По поводу листов - специально ради Вас  :) создал темку-опрос. Если хотите - подождите ответов, если загорелось срочно - пишите в личку, отвечу там.
Да нет, по поводу листов у меня нет на данный момент никаких вопросов, сам вспомнил и легко разобрался. У меня сейчас все вопросы исключительно по проходу в цикле по значениям времени.

Муж это единственный зарегенный юзер, а все остальные это хакеры :)

Олег*

Цитата: Олег* от 17.04.2013, 11:25
Я, конечно, понимаю, почему так происходит.
Там дробные значения с определенной точностью и нет точного совпадения. Поэтому приходится создавать вокруг значения "10:45" некий буфер, чтобы Эксель понял, что если значение попало в этот интервал, его надо пропустить.

И то же самое с конечным значением цикла. Экселю не хватает какой-то малюсенькой дробной частички, чтобы понять, что значение "11:00" тоже надо анализировать.

Вопрос такой:
я эту проблему решил очень сложно и, честно говоря, мне это совсем не нравится.

А можно сделать как-нибудь иначе, попроще и полаконичнее?

Может как-нибудь округлять по-хитрому?
Муж это единственный зарегенный юзер, а все остальные это хакеры :)

Serge 007

Цитата: Олег* от 17.04.2013, 11:25Я, конечно, понимаю, почему так происходит. Там дробные значения с определенной точностью и нет точного совпадения.
Ничего подобного. 10:30 всегда равно 10:30

По Exit For осуществляется выход из цикла - это раз;
Значения в цикле так не исключаются - это два;
Верхний порог в For Вы сами уменьшаете СчетчикСтрок - 1 - это три
Бесплатная помощь: www.excelworld.ru
Платная помощь: sergeyizotov@excelworld.ru
Ю-money: 41001419691823 | WMR:126292472390

Олег*

#8
Цитата: Serge 007 от 17.04.2013, 14:05
По Exit For осуществляется выход из цикла - это раз

Согласен! Это мое упущение. Дело в том, что в оригинальной программе (в отличие от приведенного примера) два цикла, вложенных один в другой, и при равенстве управляющей переменной внутреннего цикла значению "10:30", мы просто выходим из вложенного цикла во внешний цикл.

Цитата: Serge 007 от 17.04.2013, 14:05
Ничего подобного. 10:30 всегда равно 10:30

Но, кстати, в том варианте, который выложен на форуме, программа должна при достижении значения "10:30" просто закончить свою работу, а она игнорирует это условие и продолжает как ни в чем не бывало :)


Цитата: Serge 007 от 17.04.2013, 14:05
Значения в цикле так не исключаются - это два

А как?! Подскажите!
Меня сейчас совсем не интересует абстрактное теоретизирование и разработка инноваций.
Меня интересует чисто практический вопрос:

Как пройтись циклом по значениям времени от  "10:00" до "11:00" включительно  с шагом "00:15" и при этом пропустить (не обрабатывать) значение "10:30"?

Цитата: Serge 007 от 17.04.2013, 14:05
Верхний порог в For Вы сами уменьшаете СчетчикСтрок - 1 - это три

Да нет же... Эта переменная влияет только на отображение информации на листе. А управляющая переменная цикла это Время.

Private Sub CommandButton1_Click()
Dim Время As Date
Dim СчетчикСтрок As Long

    Range("A2:B100").ClearContents
   
    СчетчикСтрок = 1
    For Время = "10:00" To "11:00" Step "00:15"
   
        If Время = "10:30" Then Exit For
        СчетчикСтрок = СчетчикСтрок + 1
        Worksheets("Лист1").Range("A" & СчетчикСтрок) = СчетчикСтрок - 1
        Worksheets("Лист1").Range("B" & СчетчикСтрок) = Время
    Next Время
End Sub
Муж это единственный зарегенный юзер, а все остальные это хакеры :)

_Boroda_

#9
Private Sub CommandButton1_Click()
Dim Время As Date
Dim СчетчикСтрок As Long
    Range("A2:B100").ClearContents
    СчетчикСтрок = 1
    For Время = "10:00" To "11:00:01" Step "00:15"
        If Format(Время, "hh:mm") <> "10:30" Then
            СчетчикСтрок = СчетчикСтрок + 1
            Worksheets("Лист1").Range("A" & СчетчикСтрок) = СчетчикСтрок - 1
            Worksheets("Лист1").Range("B" & СчетчикСтрок) = Время
        End If
    Next Время
End Sub

Опытным путем установил, что для конечного значения 11:00 не считают периоды 12, 15, 20 и 30 минут. Для окончания 23:00 15 минут считает. Так что, судя по всему, это действительно из-зи округления.
Скажи мне, кудесник, любимец ба'гов...



Яндекс-деньги: 41001632713405
Webmoney: R289877159277; Z102172301748; E177867141995

Олег*

#10
Цитата: _Boroda_ от 17.04.2013, 15:25
Private Sub CommandButton1_Click()
Dim Время As Date
Dim СчетчикСтрок As Long
    Range("A2:B100").ClearContents
    СчетчикСтрок = 1
    For Время = "10:00" To "11:00:01" Step "00:15"
        If Format(Время, "hh:mm") <> "10:30" Then
            СчетчикСтрок = СчетчикСтрок + 1
            Worksheets("Лист1").Range("A" & СчетчикСтрок) = СчетчикСтрок - 1
            Worksheets("Лист1").Range("B" & СчетчикСтрок) = Время
        End If
    Next Время
End Sub

Как Вы решили проблему игнорирования значения "10:30", мне очень понравилось, а вот с "11:00:01" это, конечно, не Рио-де-Жанейро! :)

Я почему секунду-то отдельно добавляю?
У меня потом (в перспективе) начальное и конечное значение цикла будут из ячеек считываться, а я буду иметь возможность ими "играть". Поэтому мне удобнее "реальное" конечное значение вставить, а программа уже сама будет добавлять эту секунду, если уж без нее никак не обойтись :)


Цитата: _Boroda_ от 17.04.2013, 15:25
Опытным путем установил, что для конечного значения 11:00 не считают периоды 12, 15, 20 и 30 минут. Для окончания 23:00 15 минут считает.

Да вот и я тоже заметил, что на некоторых значениях этот баг вылезает, а на некоторых нет.

Цитата: _Boroda_ от 17.04.2013, 15:25
Так что, судя по всему, это действительно из-за округления.

Точнее говоря, не из-за округления, а из-за ОТСУТСТВИЯ ОКРУГЛЕНИЯ.
Программа каждый раз на новой итерации добавляет указанное значение, например, какое-нибудь 0,000074658573638956475847, а в самом конце она должна завершить цикл на каком-нибудь 0,3967584657697867586738, а у нее получается 0,3967584657697867586739, и она считает, что это значение уже превышает верхнюю границу и, следовательно, пора выходить из цикла.
А если бы было округление, то она бы поняла, что от нее требуется считать эти значения равными друг другу и продолжать выполнять цикл с этим значением. Это как раз тот самый случай, когда излишняя точность вредит делу :)
Потому-то я и думаю, что можно как-нибудь попробовать округлять?
А то с добавлением секунды какая-то все-таки кустарщина получается. Округление, конечно тоже не фонтан, но все-таки как-то более солидно выглядит, хотя и будет сказываться на скорости выполнения программы, это я понимаю.
Муж это единственный зарегенный юзер, а все остальные это хакеры :)

_Boroda_

#11
Цитата: Олег* от 17.04.2013, 16:33
Точнее говоря, не из-за округления, а из-за ОТСУТСТВИЯ ОКРУГЛЕНИЯ.
Как раз из-за округления. Точнее, округление при преобразовании из двоичного в десятеричное.
Кстати, числа 0,000074658573638956475847 в Excel быть не может. Максимум 15 цифр.
А макрос можно переписать так:
Private Sub CommandButton1_Click()
Dim Время  As Date
Dim СчетчикСтрок As Long
    Range("A2:B100").ClearContents
    СчетчикСтрок = 1
    For Время = "10:00" To "11:00" & ":01" Step "00:15"
        If Format(Время, "hh:mm") <> "10:30" Then
            СчетчикСтрок = СчетчикСтрок + 1
            Worksheets("Лист1").Range("A" & СчетчикСтрок) = СчетчикСтрок - 1
            Worksheets("Лист1").Range("B" & СчетчикСтрок) = Время
        End If
    Next Время
End Sub
Скажи мне, кудесник, любимец ба'гов...



Яндекс-деньги: 41001632713405
Webmoney: R289877159277; Z102172301748; E177867141995

Олег*

#12
Цитата: _Boroda_ от 17.04.2013, 17:08
А макрос можно переписать так:
Private Sub CommandButton1_Click()
Dim Время  As Date
Dim СчетчикСтрок As Long
    Range("A2:B100").ClearContents
    СчетчикСтрок = 1
    For Время = "10:00" To "11:00" & ":01" Step "00:15"
        If Format(Время, "hh:mm") <> "10:30" Then
            СчетчикСтрок = СчетчикСтрок + 1
            Worksheets("Лист1").Range("A" & СчетчикСтрок) = СчетчикСтрок - 1
            Worksheets("Лист1").Range("B" & СчетчикСтрок) = Время
        End If
    Next Время
End Sub


Решил остановиться вот на таком решении проблемы:

Private Sub CommandButton1_Click()
Dim Время As Date
Dim Финиш As Date
Dim СчетчикСтрок As Long
    Range("A2:B100").ClearContents
    СчетчикСтрок = 1
    Финиш = "11:00"
    Финиш = Round(Финиш, 2)
    For Время = "10:00" To Финиш Step "00:15"
        If Format(Время, "hh:mm") <> "10:30" Then
            СчетчикСтрок = СчетчикСтрок + 1
            Worksheets("Лист1").Range("A" & СчетчикСтрок) = СчетчикСтрок - 1
            Worksheets("Лист1").Range("B" & СчетчикСтрок) = Время
        End If
    Next Время
End Sub


Переменная Финиш вычисляется всего один раз, поэтому лишних тормозов не будет. Значение этой переменной впоследствии будет считываться из ячейки, т.е. ее можно будет изменять, не залезая в код.

Serge 007 и _Boroda_, большое спасибо, что помогли разобраться!
Муж это единственный зарегенный юзер, а все остальные это хакеры :)

Hugo121

Так ещё можно:
Private Sub CommandButton1_Click()
    Dim Время As Date
    Dim t As Date: t = #10:30:00 AM#
    Dim СчетчикСтрок As Long

    Range("A2:B100").ClearContents

    СчетчикСтрок = 1
    For Время = "10:00" To "11:00" Step "00:15"

        If CStr(Время) = CStr(t) Then Exit For
        СчетчикСтрок = СчетчикСтрок + 1
        Worksheets("Лист1").Range("A" & СчетчикСтрок) = СчетчикСтрок - 1
        Worksheets("Лист1").Range("B" & СчетчикСтрок) = Время
    Next Время
End Sub
webmoney: E265281470651 Z422237915069

Олег*

#14
Цитата: Hugo121 от 17.04.2013, 23:08
Так ещё можно:
Private Sub CommandButton1_Click()
    Dim Время As Date
    Dim t As Date: t = #10:30:00 AM#
    Dim СчетчикСтрок As Long

    Range("A2:B100").ClearContents

    СчетчикСтрок = 1
    For Время = "10:00" To "11:00" Step "00:15"

        If CStr(Время) = CStr(t) Then Exit For
        СчетчикСтрок = СчетчикСтрок + 1
        Worksheets("Лист1").Range("A" & СчетчикСтрок) = СчетчикСтрок - 1
        Worksheets("Лист1").Range("B" & СчетчикСтрок) = Время
    Next Время
End Sub


А можно таким способом решить не только проблему "10:30", но и проблему "11:00"?

Кстати, столкнулся еще с одной проблемой из той же серии.
Оказывается Эксель не только со значениями времени в циклах глючит, но и данными типа Single и Double.
Прилагаю простенький пример для иллюстрации. Цикл должен пробегать значения от нуля до 0,5 с шагом 0,1. Верхнее значение, как стало уже доброй традицией,  Экселем игнорируется :)

Ну и что делать?!
Снова с бубном плясать на ровном месте? :)
Добавлять одну сотую? :)
Эх, грехи наши тяжкие :(
Муж это единственный зарегенный юзер, а все остальные это хакеры :)