Как рассчитать месяц с дробью в Access VBA

Мне нужно написать функцию, которая получает два аргумента startdate и enddate, где она возвращает разницу между этими двумя датами.

Скажите, что эта функция monthfractiondiff(startdate,enddate)

например monthfractiondiff(15/01/2016,15/02/2016) вернется ((31-15)/31)+(15/29) = 1.0333704116

monthfractiondiff(15/11/2018,15/02/2019) вернется ((30-15)/30)+1+1+(15/28) = 3.0357142857

Я тщетно пытался https://access-programmers.co.uk/forums/showthread.php?t=113589

Опубликуйте фактический код, который вы пробовали, и укажите, какая его часть работает неправильно. «Тщетно пытался» может быть опечаткой в ​​том, что вы перепечатали, может быть, вы пропустили строку при копировании/вставке, трудно сказать...

FreeMan 29.05.2019 17:24

@FreeMan Я пробовал приведенный выше код (опубликованный pstraton), он работает, когда даты начала и окончания приходятся на один и тот же год, но происходит не так, когда обе даты приходятся на разные годы, например. Дата начала в 2018 году и дата окончания в 2019 году.

SIslam 29.05.2019 17:27

Посмотрите ветку, которую вы упоминаете, прокрутите вниз и попробуйте код пользователя пстратон.

FunThomas 29.05.2019 17:31

Спасибо за ответ. обновил свой комментарий. Действительно ли это работает?

SIslam 29.05.2019 17:33
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
4
307
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

ОБНОВЛЕНО благодаря другому ответу WeeBee

Function HowManyMonths(startdate As Date, Enddate As Date) As Double
Dim pctSTARTmonth As Double, pctENDmonth As Double, M As Long


'caputues percentage of month
pctSTARTmonth = Day(startdate) / Day(DateSerial(Year(startdate), Month(startdate) + 1, 1) - 1)
pctENDmonth = Day(Enddate) / Day(DateSerial(Year(Enddate), Month(Enddate) + 1, 1) - 1)


'Use Date difference function to get whole number and then combine perc
HowManyMonths = DateDiff("M", startdate, Enddate) + pctENDmonth - pctSTARTmonth


End Function

Спасибо! но он также не вычисляет правильную часть месяца, например. HowManyMonths(03 декабря 2018 г., 17 июня 2019 г.) возвращает 6.5032, что было бы 29/31+1+1+1+1+1+17/30 = 6.50215053762 or 6.5022

SIslam 30.05.2019 06:59

@SIslam, это другой подход, чем то, что вы говорили ранее. В вашем первом примере с ноябрем вы вычли дату из общего числа дней, разделенную на общее количество дней, поэтому: (30-15)/30=0.5. Но с вашим примером от 3 декабря вы показываете 29/31, что является другим подходом. Основываясь на вашем предыдущем примере, это будет равно 28, вместо этого вы 31-2 получите 29 вместо 31. Это объясняет вашу разницу. Если вы хотите указать дату начала (как вы сделали для декабрьских примеров), ее легко изменить.

pgSystemTester 30.05.2019 08:17
monthfractiondiff(15/01/2016,15/02/2016) will return ((31-15)/31)+(15/29) = 1.0333704116 Здесь (31-15) = (Total Days in that month)-Day portion of the start date
SIslam 30.05.2019 08:41

@SIslam извините, я не понимаю. Удачи с этим.

pgSystemTester 30.05.2019 08:53

Извините, если вы не понимаете. monthfractiondiff(15/01/2016,15/02/2016) вернётся ((31-15)/31)+(15/29) = 1.0333704116 Сюда (31-15) = (Total Days in January month)-(Day portion of the start date i.e. 15)

SIslam 30.05.2019 08:59

Да, я вижу, что... с 15 января по 15 февраля в високосный год равно 1,0337 (31-15) = 16/31 + 15/29. Это то, что возвращает моя формула, и это то, что вы указали в качестве ожидаемого результата в своем примере. . Это не тот же подход в вашем примере от 3 декабря, который = (31-3) = показывает ДВАДЦАТЬ ДЕВЯТЬ вместо 28, разделенных на 31.

pgSystemTester 30.05.2019 09:07

Я бы пошел с datediff().

datediff("d", "01/01/2019", date())/30.5

Сегодня это возвращает мне 4 85245901639344.

Мне больше нравится ваш общий подход (т. е. стандартизация месяца), но ОП ясно дает понять, что он / она ищет каждый месяц для преобразования в процент в относительных днях месяца. Ваша формула не совсем подходит, так как она вернет 1,0163 для примера января/февраля вместо 1,0337.

pgSystemTester 29.05.2019 18:04

Да, у моей формулы нет твоего уровня точности, это математический подход.

WeeBee 29.05.2019 18:28

Я украл часть вашего ответа (и заплатил за это кликом вверх!). DateDiff — лучший подход, чем моя идея цикла.

pgSystemTester 29.05.2019 18:37

Спасибо, @PGCodeRider!

WeeBee 29.05.2019 20:09

Поскольку количество дней в месяцах варьируется, вы должны считать по дням, чтобы получить как можно более точное значение, поскольку никогда (кроме как в течение месяца или в течение июля/августа или декабря/января) не будет точного значения:

' Rounds by default to two decimals, as more decimals has no meaning
' due to the varying count of days of a month.
' Optionally, don't round, by setting Round2 to False.
'
Public Function TotalMonths( _
    ByVal Date1 As Date, _
    ByVal Date2 As Date, _
    Optional Round2 As Boolean = True) _
    As Double

    Dim Months      As Double
    Dim Part1       As Double
    Dim Part2       As Double
    Dim Fraction    As Double
    Dim Result      As Double

    Months = DateDiff("m", Date1, Date2)
    Part1 = (Day(Date1) - 1) / DaysInMonth(Date1)
    Part2 = (Day(Date2) - 1) / DaysInMonth(Date2)

    If Round2 = True Then
        ' Round to two decimals.
        Fraction = (-Part1 + Part2) * 100
        Result = Months + Int(Fraction + 0.5) / 100
    Else
        Result = Months - Part1 + Part2
    End If

    TotalMonths = Result

End Function


' Returns the count of days of the month of Date1.
'
' 2016-02-14. Gustav Brock, Cactus Data ApS, CPH.
'
Public Function DaysInMonth( _
    ByVal Date1 As Date) _
    As Integer

    Const MaxDateValue  As Date = #12/31/9999#
    Const MaxDayValue   As Integer = 31

    Dim Days    As Integer

    If DateDiff("m", Date1, MaxDateValue) = 0 Then
        Days = MaxDayValue
    Else
        Days = Day(DateSerial(Year(Date1), Month(Date1) + 1, 0))
    End If

    DaysInMonth = Days

End Function

Результаты:

? TotalMonths(#2016/01/15#, #2016/02/15#)
 1.03 

? TotalMonths(#2018/11/15#, #2019/02/15#)
 3.03 

Кажется, довольно много усилий, чтобы получить DaysInMonth. Смотрите мой подход ниже: Day(DateSerial(Year(startdate), Month(startdate) + 1, 1) - 1)

pgSystemTester 30.05.2019 08:26

@PGCodeRider: взято из структурированной библиотеки.

Gustav 30.05.2019 09:31

Другие вопросы по теме