Liệt kê các ngày cộng dồn mong muốn vào 1 ô. Nhờ mọi người giúp mình ạ.

Liên hệ QC
Tôi tuân thủ nội quy khi đăng bài
Code này anh thêm tham số ngày kết thúc để có thể chọn được không ạ. Do trong quá trình làm em làm ngày hôm nay nhưng ngày kết thúc chọn ngày khác ạ.
Ý bạn là xác định ngày cuối thay vì ngày today()?
Trong code này mình cố định ngày cuối trong code luôn. Nếu bạn muốn chọn ngày thì thay nó bằng 1 cái InputBox nhé
ngaycuoi = DateSerial(2024, 11, 3)
giả sử ngày cuối là ngày 03/11/2024

PHP:
Option Explicit
Function listngay(ngaybd As Date, songay As Integer) As String
If ngaybd = 0 Or songay = 0 Then
    listngay = "O nay khong co so lieu!"
    Exit Function
End If
Dim c&, st As String, ngaykt As Date, ngaycuoi As Date, wf As Object
Set wf = WorksheetFunction
ngaycuoi = DateSerial(2024, 11, 3) ' thay doi ngay tuy chon. Co the thay bang InputBox de chon ngay moi khi run, neu ngay nay co su bien dong
Do
    c = c + 1
    ngaybd = ngaybd + songay
    ngaykt = wf.Min(ngaycuoi, wf.WorkDay_Intl(ngaybd - 1, 1, "0000000", Sheets("LICH NGHI LE").Range("A2:A5")))
    st = IIf(st = "", ngaykt, st & ", " & ngaykt)
    If ngaykt >= ngaycuoi Then Exit Do
Loop
listngay = st
End Function
 

File đính kèm

Ý bạn là xác định ngày cuối thay vì ngày today()?
Trong code này mình cố định ngày cuối trong code luôn. Nếu bạn muốn chọn ngày thì thay nó bằng 1 cái InputBox nhé
ngaycuoi = DateSerial(2024, 11, 3)
giả sử ngày cuối là ngày 03/11/2024

PHP:
Option Explicit
Function listngay(ngaybd As Date, songay As Integer) As String
If ngaybd = 0 Or songay = 0 Then
    listngay = "O nay khong co so lieu!"
    Exit Function
End If
Dim c&, st As String, ngaykt As Date, ngaycuoi As Date, wf As Object
Set wf = WorksheetFunction
ngaycuoi = DateSerial(2024, 11, 3) ' thay doi ngay tuy chon. Co the thay bang InputBox de chon ngay moi khi run, neu ngay nay co su bien dong
Do
    c = c + 1
    ngaybd = ngaybd + songay
    ngaykt = wf.Min(ngaycuoi, wf.WorkDay_Intl(ngaybd - 1, 1, "0000000", Sheets("LICH NGHI LE").Range("A2:A5")))
    st = IIf(st = "", ngaykt, st & ", " & ngaykt)
    If ngaykt >= ngaycuoi Then Exit Do
Loop
listngay = st
End Function
Ý là mình muốn xác định ngày cuối giống như xác định ngày bắt đầu đó ạ. Để chọn vào các ô trong excel cho tiện.
 
Mình xin được phép gởi lại file dữ liệu mong muốn nhờ mọi người giúp đỡ ạ. Em cũng đã liệt kê các ngày lễ để bỏ qua từ năm 2021 đến 2027
 

File đính kèm

Ý là mình muốn xác định ngày cuối giống như xác định ngày bắt đầu đó ạ. Để chọn vào các ô trong excel cho tiện.
Cái này đơn giản, bạn có thể tự làm được mà.
Giả sử ô C5 chứa ngày cuối
PHP:
ngaycuoi = Range("C5").value
 
Cái này đơn giản, bạn có thể tự làm được mà.
Giả sử ô C5 chứa ngày cuối
PHP:
ngaycuoi = Range("C5").value
Được ạ. Nhưng do mình cần copy kéo xuống nhiều dòng khác thì sẽ không tiện bằng cách chọn ô C5, kéo xuống thì thành C6,C7,C8 ... có ô chứa ngày cuối tương ứng ạ.
 
Mình bổ sung thêm theo yêu cầu của bạn, đặt tên list ngày nghỉ là "ngayle" để bạn có thể tùy chỉnh số lượng ngày. Hàm vẫn chưa thực sự hoàn thiện. Nhưng trong phạm vi nào đó thì mình nghĩ vẫn áp dụng được. Vì yêu cầu của bạn không mang tính phổ biến và cũng không biết dữ liệu thực của bạn thế nào nên bạn tự kiểm tra.
Mã:
Function Taochuoingay(ngaybd As Date, ngaykt As Date, kc As Long) As String
    Dim chuoingay As String
    Dim ngay As Date
    Dim ngaynghile As Range
    Dim cell As Range
    Dim trungngayle As Boolean
    
    On Error Resume Next
    Set ngaynghile = ThisWorkbook.Names("ngayle").RefersToRange
    On Error GoTo 0
    If ngaynghile Is Nothing Then
       Set ngaynghile = ActiveSheet.Range("A1")
    End If
 
    chuoingay = ""
    ngay = ngaybd + kc

    Do While ngay <= ngaykt
        trungngayle = False
        For Each cell In ngaynghile
            If ngay = cell.Value Then
                ngay = ngay + 1
                trungngayle = True
                Exit For
            End If
        Next cell
              
              If Not trungngayle And ngay <= ngaykt Then
            chuoingay = chuoingay & Format(ngay, "dd/mm/yyyy") & ", "
            ngay = ngay + kc
        End If
    Loop

    If ngay > ngaykt Then
        chuoingay = chuoingay & Format(ngaykt, "dd/mm/yyyy")
    End If
    
     If Right(chuoingay, 1) = " " Then
        chuoingay = Left(chuoingay, Len(chuoingay) - 2)
    End If

    Taochuoingay = chuoingay
End Function
 

File đính kèm

Loại thớt này là loại đề tài rác gộp.
Cứ vài thử nghiệm thì sinh ra chi tiết mới.
Hiện tượng này xảy ra khi thớt cho rằng mình có thể "túm gọn vấn đề, tìm giải pháp chính rồi thêm chi tiết sau"
Rất tiếc là thớt không biết cách túm gọn vấn đề cho nên cắt xén nhiều quá trong bài #1. Đến chnwgf nhìn thấy kết quả thì bát đầu nhét lại các phần đã bị cắt xén.
Loại bài này lắm khi bắt người viết phải viết lại code.

Và nhắc nhở các bạn viết code: chưa chắc code đã dáp ứng được chuyện lâu dài. Nhìn cái kết quả, tôi biết nó chỉ là 'sáng kiến' nhất thời của thớt. Có thể vài tháng sau thì khám phá ra nó khó đọc bỏ bố, và bỏ luôn. Vì vậy code có options này nọ chỉ uổng công thôi
 
Mình bổ sung thêm theo yêu cầu của bạn, đặt tên list ngày nghỉ là "ngayle" để bạn có thể tùy chỉnh số lượng ngày. Hàm vẫn chưa thực sự hoàn thiện. Nhưng trong phạm vi nào đó thì mình nghĩ vẫn áp dụng được. Vì yêu cầu của bạn không mang tính phổ biến và cũng không biết dữ liệu thực của bạn thế nào nên bạn tự kiểm tra.
Mã:
Function Taochuoingay(ngaybd As Date, ngaykt As Date, kc As Long) As String
    Dim chuoingay As String
    Dim ngay As Date
    Dim ngaynghile As Range
    Dim cell As Range
    Dim trungngayle As Boolean
   
    On Error Resume Next
    Set ngaynghile = ThisWorkbook.Names("ngayle").RefersToRange
    On Error GoTo 0
    If ngaynghile Is Nothing Then
       Set ngaynghile = ActiveSheet.Range("A1")
    End If
 
    chuoingay = ""
    ngay = ngaybd + kc

    Do While ngay <= ngaykt
        trungngayle = False
        For Each cell In ngaynghile
            If ngay = cell.Value Then
                ngay = ngay + 1
                trungngayle = True
                Exit For
            End If
        Next cell
             
              If Not trungngayle And ngay <= ngaykt Then
            chuoingay = chuoingay & Format(ngay, "dd/mm/yyyy") & ", "
            ngay = ngay + kc
        End If
    Loop

    If ngay > ngaykt Then
        chuoingay = chuoingay & Format(ngaykt, "dd/mm/yyyy")
    End If
   
     If Right(chuoingay, 1) = " " Then
        chuoingay = Left(chuoingay, Len(chuoingay) - 2)
    End If

    Taochuoingay = chuoingay
End Function
Cảm ơn bạn rất nhiều. Mình đã tạo được dữ liệu theo ý muốn và nó rất cần thiết cho công việc của mình thời gian lâu dài ạ. Cảm ơn mọi người đã quan tâm thớt này ạ.
 
Code dưới đây đáp ứng yêu cầu cuối cùng. Không thêm bớt yêu cầu mới gì nữa, nếu có thì tự sửa.
PHP:
Function StrDate(StartD, EndD, Cycle As Long, Holidays As Range)
Dim TmpStr As String, TmpD As Long
TmpD = StartD
Do
    TmpD = TmpD + Cycle
    For Each Cll In Holidays
        If TmpD = Cll.Value Then TmpD = TmpD + 1
    Next
    TmpStr = TmpStr & ", " & Format(TmpD, "dd/mm/yy")
Loop Until TmpD + Cycle > EndD
    TmpStr = TmpStr & ", " & Format(EndD, "dd/mm/yy")
    StrDate = Mid(TmpStr, 3, Len(TmpStr))
End Function

Cú pháp:
=StrDate(ngày đầu, ngày cuối, chu kỳ, vùng ngày lễ)

1730480344057.png
 
Code dưới đây đáp ứng yêu cầu cuối cùng. Không thêm bớt yêu cầu mới gì nữa, nếu có thì tự sửa.
PHP:
Function StrDate(StartD, EndD, Cycle As Long, Holidays As Range)
Dim TmpStr As String, TmpD As Long
TmpD = StartD
Do
    TmpD = TmpD + Cycle
    For Each Cll In Holidays
        If TmpD = Cll.Value Then TmpD = TmpD + 1
    Next
    TmpStr = TmpStr & ", " & Format(TmpD, "dd/mm/yy")
Loop Until TmpD + Cycle > EndD
    TmpStr = TmpStr & ", " & Format(EndD, "dd/mm/yy")
    StrDate = Mid(TmpStr, 3, Len(TmpStr))
End Function

Cú pháp:
=StrDate(ngày đầu, ngày cuối, chu kỳ, vùng ngày lễ)

View attachment 305212
Cảm ơn anh rất nhiều ạ. Code chạy rất tốt đáp ứng nhu cầu làm việc thường xuyên của em ạ
 
Bẫy lỗi trường hợp ngày cuối cách ngày đầu đúng 1 chu kỳ:
Mã:
Function StrDate(StartD, EndD, Cycle As Long, Holidays As Range)
Dim TmpStr As String, TmpD As Long
Dim Cll As Variant
TmpD = StartD + Cycle

Do While TmpD < EndD
    For Each Cll In Holidays
        If TmpD = Cll.Value Then TmpD = TmpD + 1
    Next
    TmpStr = TmpStr & ", " & Format(TmpD, "dd/mm/yy")
    TmpD = TmpD + Cycle
Loop
    TmpStr = TmpStr & ", " & Format(EndD, "dd/mm/yy")
    StrDate = Mid(TmpStr, 3, Len(TmpStr))
End Function
 
Lần chỉnh sửa cuối:
Đúng là tôi chưa test trường hợp này. Có thể thêm 1 điều kiện If nhưng cách của bạn hay hơn.
Còn trường hợp 2 ngày nghỉ liên tiếp thì chỉ lên 1 ngày ạ. Ví dụ: trúng ngày 30/4/2024 thì nó chỉ nhảy lên 1 ngày là 1/5/2024 chứ không nhảy qua ngày 2/5/2024.
 
Còn trường hợp 2 ngày nghỉ liên tiếp thì chỉ lên 1 ngày ạ. Ví dụ: trúng ngày 30/4/2024 thì nó chỉ nhảy lên 1 ngày là 1/5/2024 chứ không nhảy qua ngày 2/5/2024.
Kết quả mong muốn bạn đưa lên ở bài 45 là 2/5. Bài 47 bạn còn cãi với bài 46.
Tôi đã nói là không xí quên, không xí lộn, không thêm bớt. Bạn phải tự sửa.

1730509875291.png
 
Đúng là tôi chưa test trường hợp này. Có thể thêm 1 điều kiện If nhưng cách của bạn hay hơn.
Chưa chắc là hay đâu anh, bẫy này vẫn để "sổng" lỗi khi ngày liền trước ngày kết thúc là ngày kết thúc chu kỳ đồng thời là ngày lễ.
--
Ngoài ra code còn một lỗi khá nghiêm trọng là sẽ rơi vào vòng lặp vô tận khi số ngày một chu kỳ bằng 0 (có thể do vô tình xóa ô chứa giá trị số ngày một chu kỳ).
--
Còn cái vế "lớn hơn ngày hiện tại thì ngày cuối cùng là ngày kết thúc" trong yêu cầu thì không hiểu ý nói gì, code cũng chưa thực hiện.
 
Web KT

Bài viết mới nhất

Back
Top Bottom